给定范围 [m, n]
,其中 0 <= m <= n <= 2147483647
,返回此范围内所有数字的按位与
(包含 m, n
两端点)。
示例 1:
输入: [5,7]
输出: 4
示例 2:
输入: [0,1]
输出: 0
题意 : 求区间 [ L , R ] [L,R] [L,R]内所有
数字的按位与
例如 : [ 3 , 6 ] [3,6] [3,6]的 a n s = 3 & 4 & 5 & 6 = 0 ans=3\&4\&5\&6=0 ans=3&4&5&6=0
灯神
的讲解视频 : https://www.bilibili.com/video/BV1wp4y1X768?t=8假设 L = 100101001 , R = 100101101 L=100101001,R=100101101 L=100101001,R=100101101
L = 1001010
01
R = 1001011
01
观察 ( L + 0 ) & ( L + 1 ) & ( L + 2 ) . . . . & R (L+0)\&(L+1)\&(L+2)....\&R (L+0)&(L+1)&(L+2)....&R的过程
L+0 = 100101 001
L+1 = 100101 010
L+2 = 100101 011
L+3 = 100101 100
R = 100101 101
-------------
res = 100101 000
可以发现由于二进制后3
位不相同
,于是&
后变成了全0
方法一 :
区间 [ L , R ] [L,R] [L,R]的&
可以变成从左往右
找第一个二进制位不同的
位置开始,往后所有位置置为0
就是答案
时间复杂度为 O ( 1 ) O(1) O(1)
方法二 :
直接把两个数字一起右移,直到相等
方法三 :
Brian Kernighan 算法 : 把二进制最后一位1
设置为0
核心 : X = X & ( X − 1 ) X=X~\&~(X-1) X=X & (X−1)
代码如下
int rangeBitwiseAnd(int m, int n) {
#if 0
//方法一,从左往右找出第一个不相同的数字
int ret = 0;
int i = 31;
while(i >= 0 && ((m>>i)&1) == ((n>>i)&1)) {
if(m>>i&1) setbit(ret, i);
i --;
}
return ret;
#elif 0
//方法二,直接把两个数一起右移,直到相等
int cnt = 0; //统计右移了多少位
while(n != m)
n >>= 1, m >>= 1, cnt ++;
return n << cnt; //记得要把n再移回去
#elif 1
//方法三 : Brian Kernighan 算法
//Brian Kernighan 算法 : 可以把二进制的最后一位1设置为0
//核心 : x = x & (x-1)
int L = m, R = n;
while(L < R) {
R = R & (R - 1);
}
return R & L;
#endif
}