201. 数字范围按位与

113 阅读1分钟

题目

给你两个整数 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

因此,这题可以转换成求 leftright两个整数的二进制字符串的公共前缀

具体操作,我们可以使用位移的方法

  • 首先, 将两个数字不断向右移动,直到数字相等,即数字被缩减为它们的公共前缀
  • 然后,通过将公共前缀向左移动,将零添加到公共前缀的右侧,即可获得最终结果

复杂度分析

时间复杂度: O(logN), 算法的复杂度取决于 leftright的二进制位,由于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;
};