题目
给你两个整数 left 和 right ,表示区间 [left, right] ,返回此区间内所有数字 按位与 的结果(包含 left 、right 端点)。
示例 1:
输入: left = 5, right = 7
输出: 4
示例 2:
输入: left = 0, right = 0
输出: 0
示例 3:
输入: left = 1, right = 2147483647
输出: 0
提示:
0 <= left <= right <= 231 - 1
题解
这道题如果直接使用依次迭代 [left, right]范围内的每个数字,依次做按位与运算,尽管最终会得到正确的结果,但在较大的[left, right]范围的测试用例中会超时而无法通过
位运算的性质: 对于一系列的位,如[1,1,0,1,1], 只要一个为零的位,那么这系列位的按位与运算结构都为零
在这道题目中,以示例一为例,将left = 5, right = 7, 我们将每个数字的二进制字符串位置对齐:
公共前缀
5:0000 0101
6:0000 0110
7:0000 0111
---------
公共前缀为 1
公共前缀右侧补0, 即二进制的100,最后返回整数4
因此,这题可以转换成求 left和right两个整数的二进制字符串的公共前缀
具体操作,我们可以使用位移的方法
- 首先, 将两个数字不断向右移动,直到数字相等,即数字被缩减为它们的公共前缀
- 然后,通过将公共前缀向左移动,将零添加到公共前缀的右侧,即可获得最终结果
复杂度分析
时间复杂度: O(logN), 算法的复杂度取决于 left和right的二进制位,由于left <= right, 因此时间复杂度取决 right的二进制位数
空间复杂度:O(1), 只需要常数空间存储若干变量
代码
/**
* @param {number} left
* @param {number} right
* @return {number}
*/
var rangeBitwiseAnd = function(left, right) {
let shift = 0;
while(left < right) {
left >>= 1;
right >>= 1;
++shift;
}
return left << shift;
};