关于位运算的骚操作只有你不懂?
位移运算的特性
-
& (与),两个数都为1相与结果为1,除此之外都为0。
-
| (或),两个数只要有其中一个为1,结果为1。
-
~ (非),这是对单数操作的取反操作,1的非是0,0的非是1。
-
^ (异或),两个数不同异或结果为1,相同为0。例如:
1 ^ 0=1,1 ^ 1=0,0 ^ 0=0。 -
>> 左移,所有数全部向左移动,这里均指逻辑左移,相当于结果乘2。
-
<< 右移,所有数全部向右移动,这里均值逻辑右移,相当于结果除2。
1、判断奇偶性
奇偶性的判断准则是能否被2整除,在二进制的世界里只要末尾非1即可。根据与的原则可以用以下处理。
n & 1 == 1?奇:偶
2、求一个数2的次方
根据每左移一位相当于乘2的原则,则
x*(2^n)=x<<n。
3、交换变量
int a,b;交换a、b不引用中间变量,根据异或的性质,相同的数异或为0,不同的数异或为1,则实现交换只需要 a=ab;b=ab;a=a^b;
相当于a = a ^ a ^ b; b = a ^ a ^ b ^ a; 所以a = b,b = a;
4、假设一个数组中只有一个数出现过1次,其余均出现2次,找出出现一次的这个数
这是leetcode里面的一道题,这里面主要是利用了异或的性质,两个相同的数异或为0,所以只需要整个数组都异或,剩下的就是要找的那个数。
for(int i = 0;i<a.length;i++) x ^= a[i];
这里面也可以找出2个数出现1次,三个数出现1次,可以自行研究,方法类似,稍微拓展了一些。
5、求二进制数中1的个数
这个题也是利用了与的性质,,总的时间复杂度为O(n)。
for(int i = 0;i<<length;i++){
num = num >> i;
if (num & 1 != 0){
count++;
}
}
6、正整数n,找出大于n,并且最接近2的次方
看过jdk中hashmap源码的人一定知道,扩容的时候用的就是这个方法,md太精妙了。解释一下思路:就是要找到最高位是1,然后将最高位左移一位,最开始将最高位和次位变成1,
int n = cap - 1;
n |= n >>> 1;
然后由2为变成4位,4位变成8位,8位变成16位,16位变成32位,最后加个1就可以将原来的最高位左移1位,低位全部变成0,只用了5次运算,时间复杂度直接是常数。
static final int MAXIMUM_CAPACITY = 1 << 30;//将最高位致1,除符号位外
static final int tableSizeFor(int cap) {
int n = cap - 1;
n |= n >>> 1;
n |= n >>> 2;
n |= n >>> 4;
n |= n >>> 8;
n |= n >>> 16;
return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
关注公众号:计算机基础爱好者
致力于更多干货内容输出