《每周一个算法题》-位运算

489 阅读2分钟

先理解与,或,异或

符号描述运算规则
&两个位都为1,结果才为1
l两个位都为0,结果才为0
异或两个位相同为0,相异为1

算法中常用的位运算操作:

  • X & 1 ==1 or ==0 判断奇偶性(X%2==1)
  • X=X & (X-1) 清零最低位的1
  • X & -X 得到最低位的1

^ 可以被叫做无进制加法,所以异或运算的结果只取决于相同位置上的1的个数。

比如 a ^ b ,如果个位上有1个1,那么各位就为1,如果有两个1,那么个数就为0,其他位置同理。

所以满足交换律: (a ^ b) ^ c =a ^( b ^ c)

还有个特性:N ^ 0 =N , N ^ N =0

1.判断一个数是否是奇数还是偶数

解法一:直接与2取模,看结果是否等于0

public boolean isEven(int x){
    return (x % 2) == 0
}

解法二:判断一个数是否为偶数,也就是说判断该数的二进制数最后一位是否为0,任何数与1(二进制的1是0001)做与运算,也就是计算该数的最后一位与1做与运算,只有最后一位为1,那么就为奇数,为0则为偶数。

public static boolean isEven(int x) {
    return (x & 1) == 0;
}

2.判断一个数是否是2的N次幂

思路:2的n次幂的二进制数都有一个规律,就是首位为1,其余为都为0。譬如2--10 ,4--100,8--1000,16--10000等等 而上面例子中的x&(x-1)可以清零二进制中最低位一个1

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

3. 花式交换两个不同元素

在很多排序的场景下,都有交换两个元素的操作,一般为下:


public void swap (int[] arr, int i , int j){

int temp = arr[i];

arr[i] = arr[j];

arr[j] = temp;

}

在这个场景下,就可以利用异或操作来改进一下


public void swap (int[] arr, int i , int j){

arr[i] = arr[i] ^ arr[j];

// 第二步

arr[j] = arr[i] ^ arr[j];

// 第三步

arr[i] = arr[i] ^ arr[j];

}

原理:第二步中,把arr[i]替换成arr[i] ^ arr[j],这里变成arr[j] = arr[i] ^ arr[j] ^ arr[j],满足交换律,变成arr[j] = arr[i] ^ (arr[j] ^ arr[j] )。

由于N ^ N =0,所以arr[j] = arr[i] ^ 0 =arr[i];第三部分析同上。

要注意,这里的 i != j,要不然 arr[i] = arr[i] ^ arr[j] 就等于 0 。实际场景中还是不建议玩这种骚操作。 切记!!!