关于位运算的一些简单技巧
位运算
与、或、非、异或、左移
右移:
无符号右移: >>> 高位补0
有符号右移: >>
- 逻辑右移: 高位补0
- 算术右移: 高位补符号位。
在 Java 中,明确规定了:
-
逻辑右移:>>> 补0
-
算术右移:>> 补符号位
因为可以代替除法运算,算术右移一位相当于 除以 2, 高位补符号位就还是负数,补0就是正数了。。
(也可以对对比着: 左移右移一位,在十进制中,也会相应的乘10 或 除10 运算。)
奇淫技巧
-
x & 1 == 1 , 判断偶数。。。
-
不使用第三方变量,交换2个数: 使用 异或。。。。(但注意不要在数组中这样用。。。直接改变值了。)
-
x & (x - 1) ,可以将最右边一位的1(不一定是所有数的最后一位,可能在中间的位置),搞成0。
- 判断 2的幂次方。LeetCode231题
- 查找1的个数。LeetCode191题。
看原数字的二进制数,用每一位上的数字,和1与运算。(需要用到 左移运算。。。)
用 != 0 来判断,不要用==1来判断(判断的是十进制数) - 一个数,变成另一个数,改变了多少个bit位。
- 判断 2的幂次方。LeetCode231题
-
两个相同的数 异或,结果是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 ] )
-