给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。
示例 1:
输入: [5,7]
输出: 4
示例 2:
输入: [0,1]
输出: 0
思路分析:
不难发现,只有当区间[m,n]中所有的数字的某一为都为1时,对应的结果这一位才能为1,所以我们统计区间每个数的每一位即可。(时间复杂度O(n - m),额外的空间复杂度O(1))
class Solution {
public:
int rangeBitwiseAnd(int m, int n) {
int result = 0, bitCnt = 0, tempValue = 1;
//对区间的每个数分别进行32位检测
while (bitCnt < 32) {
tempValue = (1 << bitCnt);
//检测[m,n]区间中各个数第bitCnt位是否为零,如果一致都为1,说明result这1位也为1,否则为零
long long num = m;
for (; num <= n; ++num) {
if ((tempValue & num) == 0) {//这个num的第bitCnt位为零(从低到高数)
break;
}
}
if (num > n) {//如果通过了所有测试,说明[m,n]区间第bitCnt都为1
result ^= tempValue;
}
bitCnt += 1;
}
return result;
}
};
方法二:当一个数与这个数+1进行按位后,这个数的某一位后面的1将会全部置零。
比如:
当(m,m+1,…n-1,n)进行连续“与操作”时,会按照上述规律被抵消很大一部分,而只剩下n的前缀部分,最后只需将n归位。
class Solution {
public:
int rangeBitwiseAnd(int m, int n) {
int offset = 0;//标记移动的位数
//一直右移,直到相等
while(m != n){
m >>= 1;
n >>= 1;
offset += 1;
}
//最后需要往左移回去
return n << offset;
}
};