关于位运算的一些简单技巧

位运算

与、或、非、异或、左移

右移:

无符号右移: >>> 高位补0

有符号右移: >>

  • 逻辑右移: 高位补0
  • 算术右移: 高位补符号位。

在 Java 中,明确规定了:

  • 逻辑右移:>>> 补0

  • 算术右移:>> 补符号位

    因为可以代替除法运算,算术右移一位相当于 除以 2, 高位补符号位就还是负数,补0就是正数了。。
    (也可以对对比着: 左移右移一位,在十进制中,也会相应的乘10 或 除10 运算。)

奇淫技巧

  1. x & 1 == 1 , 判断偶数。。。

  2. 不使用第三方变量,交换2个数: 使用 异或。。。。(但注意不要在数组中这样用。。。直接改变值了。)

  3. x & (x - 1) ,可以将最右边一位的1(不一定是所有数的最后一位,可能在中间的位置),搞成0。

    • 判断 2的幂次方。LeetCode231题
    • 查找1的个数。LeetCode191题。
      看原数字的二进制数,用每一位上的数字,和1与运算。(需要用到 左移运算。。。)
      用 != 0 来判断,不要用==1来判断(判断的是十进制数)
    • 一个数,变成另一个数,改变了多少个bit位。
  4. 两个相同的数 异或,结果是0; 一个数和0异或,结果是他本身。 可以用来找数。

    • LeetCode136题。 一个非空整型数组,只有1个数字出现了1次(找到这个数),其余都出现了2次。
      对 所有数字 进行异或运算即可,两个相同的数字都归0了。。。

    • 进阶版本: LeetCode 137题:
      一个非空整型数组,只有1个数字出现一次(找到这个数),其余都出现了3次。
      思路1: 2个相同的数字,我们用异或,使其归0了。对于3个相同的数字,我们是不是也可以使其归0?

      所以我们对数组中的数字(二进制形式来看),一个bit一个bit的来看,就知道只出现1次的那个数了,
      举个栗子,数组:[ 6,6,4,6 ]

      相应的,该题再换出现4次、5次、6次等等,还是找只出现1次那个数,相应对4、5、6求余也就可以。
      这题该给个代码:

          public static int process(int[] nums) {
             
               int res = 0;
               for (int i = 0; i < 32; i++) {
               // int 型有32位,一位一位的来看1的个数。
                   int oneNumber = 0;      // 每看一个bit位,该遍历都需重置为0
                   for (int num : nums) {
             
                       oneNumber = oneNumber + ((num >> i) & 1);
                 
                   // 1的个数总共有几个
                   // 3个1就抵消位0; 只会出现 3 的倍数个,或者多出来 1 个; 最后的结果也就是 0 或 1
                   oneNumber = oneNumber % 3;
                   // 在当前的这一位,也就是第 i 位上,赋予他应有的值: 0 或 1.
                   res = res | (oneNumber << i);
             
               // 以上流程,32位,每一位都走完,即得到结果。
               return res;
           }
      

      思路2: 数学解法,先去重,贴个图就一目了然了:( 比如数组: [ a,a,a,b,b,b,c ] )