LeetCode位运算(找出落单的数,二进制中1的个数,2的幂等)

文章目录

  • 位运算理论+技巧介绍
    • 1.与 &
    • 2.异或 ^
    • 3.移位及综合运用(指定位置)
    • 4.同或
  • 开撸
    • 1. lc136 只出现一次的数字
    • 2. lc137 只出现一次的数字II
    • 3. lc260 只出现一次的数字III
    • 4. lc268 丢失的数字
    • 5. lc191. 位1的个数
    • 6. lc 231 2的幂
    • 7. lc1356 根据数字二进制下 1 的数目排序
  • 推荐题目列表

位运算理论+技巧介绍

对于位运算的基础还有不熟悉的可以参考这篇:位运算操作符

1.与 &

表达式 含义
(x & 1) == 1 奇数,等价于 x % 2 == 1
(x & 1) == 0 偶数,等价于 x % 2 == 0
x & (x - 1) 把x最低位的二进制1给去掉
x & -x 获取x最低位的1

2.异或 ^

性质 表达式
交换律 a ^ b ^ c <=> a ^ c ^ b
任何数与 0 异或 为任何数 0 ^ n => n
相同的数 异或 为0 n ^ n => 0

3.移位及综合运用(指定位置)

功能 表达式
x ∗ 2 n x * 2^n x2n x << n
x / 2 n x / 2^n x/2n x >> n
将 x 最右边的n位清零 x & (~0 << n)
获取 x 的第n位二进制值 (x >> n) & 1(从低到高位算,从第0位开始)
获取 x 的第n位的幂值 x & (1 << n)
仅将 x 的第n位 置为1 x | (1 << n)
仅将 x 第n位置为0 x & (~(1 << n))
将 x 最高位至第n位(含)清零 x & ((1 << n) - 1)
将 x 的第n位至第0位(含)清零 x & (~((1 << (n + 1)) - 1))

4.同或

注意Java中没有同或,可以用异或取反

开撸

1. lc136 只出现一次的数字

力扣136链接

描述:

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素

示例:

输入: [4,1,2,1,2]
输出: 4

Solution
此题在哈希表中也出现过,leetcode哈希表(哈希集合,哈希映射)
当时第一反应肯定是用HashSet的去重性

但是如果想要线性复杂度,就要想到用位运算。利用的就是异或的性质

  public int singleNumber(int[] nums) {
        int res=0;   // 0与任意数异或为任意数
        
        // 对每个数进行相互异或,相同的全变成了0
        for(int n:nums)
        res^=n;
        // 最后只剩下那个只出现一次的数字
        return res;
    }

2. lc137 只出现一次的数字II

力扣137链接

描述:

给你一个整数数组 nums ,除某个元素仅出现 一次 外,其余每个元素都恰出现 三次 。请你找出并返回那个只出现了一次的元素。

示例:

输入:nums = [0,1,0,1,0,1,99]   输出:99

Solution:

与上题很相似,但又觉得有些困难。当然,可以用哈希的方法(关于次数的题目大多和哈希有关)

还是从原始出发,依次计算最终答案的各个二进制位,一张图表明:

LeetCode位运算(找出落单的数,二进制中1的个数,2的幂等)_第1张图片

1.对于出现三次的数字,各位出现的次数都是3的倍数

2.统计所有数字的各二进制位中1的个数,并对3取余,结果位只出现一次的数字

3.对于数组中的每一个元素 x,我们使用位运算(x >> i) & 1 得到 x 的第 i 个二进制位(将第 i 位移到最低位与1相与,得到结果,因为1和0 和1 相与 为其自身)

4.将它们相加再对 3取余,得到的结果一定为 0 或 1,即为答案的第 i 个二进制位

代码

 public int singleNumber(int[] nums) {
    // 初始化一个数组,用来记录结果的各个二进制位
     int[] tmp = new int[32];
     // 统计所有数字的各个二进制位的个数
        for(int num:nums)
        {
            for(int i=0;i<32;i++)
            {
            // 将第 i 位移到最低位与1相与,得到结果
                if(((num>>i)&1)==1)
                    tmp[i]++;
            }
        }
        // ans 位最终结果
        int ans=0;
        for(int i=0;i<32;i++)
        {
        // 对于各个位不为0的
        if ((tmp[i] % 3 & 1) == 1) {
              // 将二进制转化位十进制,1<
                ans+= (1 << i);
            }
        }
   return ans;
}

稍微改进一下,不用辅助空间,直接处理:

 public int singleNumber(int[] nums) {
        int ans = 0;
        for (int i = 0; i < 32; ++i) {
            int total = 0;
            for (int num: nums) {
                total += ((num >> i) & 1);
            }
            if (total % 3 != 0) {
                ans |= (1 << i);
            }
        }
        return ans;
    }

3. lc260 只出现一次的数字III

力扣260链接

描述:

给你一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

示例:

输入:nums = [1,2,1,3,2,5]   输出:[3,5]

Solution:

4. lc268 丢失的数字

力扣268链接

描述

给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

示例

输入:nums = [3,0,1]   输出:2

Solution:
此题与lc136 有异曲同工之妙,只需要多想一步
将这n个数与1~n 这n+1个数放在一起,共2n+1个数一起异或,最后的结果就是缺失的数

public int missingNumber(int[] nums) {
     int res = 0;
     for(int i=0;i<nums.length;i++)
     {
         res ^= i;
         res ^= nums[i];
     }
     // 这里如果一开始的res初始化为数组长度,那最后输出就直接res
     return res^nums.length;
}

5. lc191. 位1的个数

描述

编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 ‘1’ 的个数(也被称为汉明重量)

示例

输入:00000000000000000000000000001011
输出:3

Solution:
利用最开始总结的技巧:n&(n-1) 去除二进制的低位1来计算二进制的1

 public int hammingWeight(int n) {
        int count=0;
        
        while(n!=0)
        {
            n &= (n-1);
            count++;
        }
        return count;
        
}

6. lc 231 2的幂

力扣231链接

描述

给你一个整数 n,请你判断该整数是否是 2 的幂次方。如果是,返回 true ;否则,返回 false 。

示例

输入: n = 16   输出: true

Solution1:
和上一题有异曲同工之妙

因为2的幂次方的二进制只有1位是1,所以把最低位去掉之后就成了0。利用上面提到的 n & (n-1)

 public boolean isPowerOfTwo(int n) {
        return n>0 && ((n & (n-1))==0);
    }

Solution2:
利用n & (-n) 可以获取最低位的1

public boolean isPowerOfTwo(int n) {
        return n > 0 && (n & -n) == n;
    }

7. lc1356 根据数字二进制下 1 的数目排序

力扣1356链接

描述

给你一个整数数组 arr 。请你将数组中的元素按照其二进制表示中数字 1 的数目升序排序。
如果存在多个数字二进制中 1 的数目相同,则必须将它们按照数值大小升序排列。
请你返回排序后的数组。

示例

输入:

Solution:

推荐题目列表

题号 难度
easy

链接:https://leetcode.cn/problems/power-of-two/solution/5chong-jie-fa-ni-ying-gai-bei-xia-de-wei-6x9m/

你可能感兴趣的:(LeetCode刷题,leetcode,算法,数据结构,位运算)