LeetCode201 Bitwise AND of Numbers Range
Description
Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive.
For example, given the range [5, 7], you should return 4.
The signature of the C++ function:int rangeBitwiseAnd(int m, int n)
题解
分析
最直接的方法:brute force。毫无疑问,经过n - m次与操作,一定可以得到解,时间复杂度O(n - m)。但是,如果n很大,且m远小于n会发生什么情况呢?此时,时间复杂度为O(n)。
Can We Do Better?
先观察与运算的特性,经过一连串的与操作,只要某个位上出现过1次0,在最终的结果中,这个位就必定为0。我们可以从m,通过每次增加1,经过n-m步加1操作,就能得到n。在二进制下观察这n-m步操作,会发现每一步都会有某些位上的数从1变为0,或者从0变为1。而且,变化的位置都集中出现在右端,从某个位置开始,再往左的数位不会发生变化。那些始终不变化的数位,在经过n-m次与操作后,依旧会保持不变。那些曾经出现改变的位,其值必定在某个时刻是0,要么原始值是0,要么原始值是1但是经过变化后变成0,在最后的结果中,这些位必定是0。
这样,我们的任务转化为了如何求出有右端有多少个数位发生了变化。
在那n-m次加1操作中,可很好地观察到,n-m的二进制表示的位数要么和发生过改变的位的数目相等,要么小1(最后一次加操作有进位)。
十进制 | 二进制 |
---|---|
1 | 00001 |
2 | 00010 |
3 | 00011 |
4 | 00100 |
5 | 00101 |
6 | 00111 |
核心代码
int res = 0;
int bitMask = 2147483647;
int diff = n - m;
int bitNum = 0;
while(diff != 0)
{
diff >>= 1;
++bitNum;
bitMask >>= 1;
}
bitMask <<= bitNum;
bitMask &= m;
res = n & bitMask;
return res;
时间复杂度:0(1)。while循环最多走32次(只需要log(n-m)次)。