https://leetcode.com/problems/bitwise-and-of-numbers-range/
Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numbers in this range, inclusive.
Example 1:
Input: [5,7] Output: 4
Example 2:
Input: [0,1] Output: 0
由于AND的性质,针对某一位,只需要判断在整个范围中的所有数字在这一位上是否存在为0的可能。注意到针对特定位,连续的数字在这一位上表现为连续的0和连续的1,同时连续数字出现的次数从一开始每次翻倍,因此针对某一位i有两种情况:
1、数据的总数超过了当前位的最大连续数字数(1<<i),此时必然存在为0的数
2、数据的总数小于等于最大连续数字数。注意到当前位全为1要求整个数据集中所有数的0~i位均落在[1<<i, 1<<(i+1)-1]这个范围中,由于mn的选择是任意的(不对齐),所以不能简单的通过(mm >= (1<<i) && nn <= 1<<(i+1)-1)进行判断,而是确定底数后加上数据集总数得到“广义上界”再与1<<(i+1)-1进行比较。
class Solution {
public:
int rangeBitwiseAnd(int m, int n) {
unsigned thre = 1;
unsigned result = 0;
unsigned mm = m;
unsigned nn = n;
unsigned num = nn-mm+1;
for(int i = 0; i < 31; ++i){
// cout << "i: " << i << endl;
// cout << "thre: " << thre << endl;
if(num > thre){
//do nothing;
}else{
unsigned mask = ((unsigned)1<<(i+1))-1;
unsigned tem = mm & mask;
// cout << "mask: " << mask << endl;
// cout << "tem: " << tem << endl;
if(tem >= (1<<i) && tem+num-1 <= mask){
result |= (1 << i);
}
}
thre <<= 1;
}
return result;
}
};
还有另一种算法就是找到m和n的最长相同前缀,这是因为针对任何一个m与n不同的位,有两种情况:
1、m为0,n为1,则从m到n必然会经历(这一位)1000...000(最低位)这一步,则必然均为0。
2、m为1,n为0,同上(因为进位)。
class Solution {
public:
int rangeBitwiseAnd(int m, int n) {
int shift=0;
while(m!=n)
{
m>>=1;
n>>=1;
shift++;
}
return m<<shift;
}
};