LeetCode201-数字范围按位与
题目
给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。
输入: [5,7]
输出: 4
输入: [0,1]
输出: 0
解法
方法一:暴力(超时)
方法二:
m和n有以下几个情况:
(1)m=n 返回m
(2)m=0 返回0
(3)m=1 返回0
(4)n/m > 1证明所有的与操作结果都是0
思路:
如果m到n此范围内所有数字的按位与的话,m和n的最高位的1必须在相同位置,然后有相同的前缀。
class Solution {
public int rangeBitwiseAnd(int m, int n) {
if(m==n) return m;
if(m<2) return 0;
//剪枝
if(n/m>1) return 0;
int bitm = 1, bitn = 1;
while(m/bitm>1){
bitm <<= 1;
}
while(n/bitn>1){
bitn <<= 1;
}
if(bitn>bitm) return 0;
int res = 0;
while((m&bitm)==(n&bitm)){
res += m&bitm;
bitm >>= 1;
}
return res;
}
}
方法二的优化方法
class Solution {
public int rangeBitwiseAnd(int m, int n) {
int shift = 0;
// 找到公共前缀
while (m < n) {
m >>= 1;
n >>= 1;
++shift;
}
return m << shift;
}
}
方法三:Brian Kernighan 算法
它用于清除二进制串中最右边的 1。
n&(n-1)可以清除二进制串中最右边的 1。
class Solution {
public int rangeBitwiseAnd(int m, int n) {
while (m < n) {
// 抹去最右边的 1
n = n & (n - 1);
}
return n;
}
}