异或小知识

  • >> 带符号位右移 高位根据符号位补齐
  • >>> 不带符号位右移 高位都用0补齐
  • mid = (L + R) / 2 写成 mid = L + ((R-L) >> 1) 防止溢出
  • n * 2 可以写成 n << 1
  • (n * 2)+1 可以写成 ((n << 1) | 1)

异或运算

异或运算:相同为0,不同为1
同或运算:相同以1,不同为0
所以,异或运算就记成无进位相加!

  • 异或运算的性质
    0^N == N
    N^N == 0
    异或运算满足交换律和结合率(同一批数,异或起来的结果是一样的)
    上面的两个性质用无进位相加来理解就非常的容易

  • 如何不用额外变量交换两个数 (a,b在不同内存)

a = a ^ b;
b = a ^ b;
a = a ^ b;
  1. 一个数组中有一种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这种数
准备一个 int eor = 0;
与数组中的所有数异或,最后eor的值就是这种数。
因为偶数的本身异或都为0了,奇数异或是本身。
// arr中,只有一种数,出现奇数次
    public static void printOddTimesNum1(int[] arr) {
        int eor = 0;
        for (int i = 0; i < arr.length; i++) {
            eor ^= arr[i];
        }
        System.out.println(eor);
    }

  1. 怎么把一个int类型的数n,提取出最右侧的1来
用 n & ((~n) + 1);
 n   = 0 ... 0 1 1 0 1 0 1 0 0 0 0
~n   = 1 ... 1 0 0 1 0 1 0 1 1 1 1
~n+1 = 1 ... 1 0 0 1 0 1 1 0 0 0 0

ans  = 0 ... 0 0 0 0 0 0 1 0 0 0 0 
  1. 一个数组中有两种数出现了奇数次,其他数都出现了偶数次,怎么找到并打印这两种数
假设2种数是a,b.
eor 先与数组所有数异或,那么eor = a ^ b != 0,那么 a,b中一定有一位是不一样的,假设他们第8位不一样。
整个数组可以分为
1.第8位=1的
2.第8位=0的
那么a,b是在这2个不同的组。
再找有个变量 eor‘ 去同第一组异或,那第一组中偶数的都为0了,剩下的结果就是eor’ = a(设a分在第一组)。
那么 eor ^ eor' = b.

// arr中,有两种数,出现奇数次
    public static void printOddTimesNum2(int[] arr) {
        int eor = 0;
        for (int i = 0; i < arr.length; i++) {
            eor ^= arr[i];
        }
        // eor = a ^ b
        // eor != 0
        // eor必然有一个位置上是1
        // 0110010000
        // 0000010000
        int rightOne = eor & (~eor + 1); // 提取出最右的1
        int onlyOne = 0; // eor'
        for (int i = 0 ; i < arr.length;i++) {
            //  arr[1] =  111100011110000
            // rightOne=  000000000010000
            if ((arr[i] & rightOne) != 0) {
                onlyOne ^= arr[i];
            }
        }
        System.out.println(onlyOne + " " + (eor ^ onlyOne));
    }

  1. 计算二进制中有几个1
public static int bit1counts(int N) {
        int count = 0;
        
        //   011011010000
        //   000000010000     1
        
        //   011011000000
        // 
        
        
        
        while(N != 0) {
            int rightOne = N & ((~N) + 1);
            count++;
            N ^= rightOne;
            // N -= rightOne
        }
        
        
        return count;
        
    }

你可能感兴趣的:(异或小知识)