201. 数字范围按位与

201. 数字范围按位与

[此处请插入:二进制公共前缀匹配过程示意图]

✨核心逻辑

本题采用 寻找公共前缀(位移法) 的策略:

  1. 核心规律:对区间 [left, right] 内的所有数字进行按位与运算,结果实际上等于 leftright 的二进制公共前缀,然后在后面补上足够数量的 0
  2. 寻找公共前缀:我们可以通过一个 while 循环,不断将 leftright 同时向右移位(相当于除以 2)。当 left < right 时,说明它们的二进制在低位还不一致,继续移位。
  3. 记录补零位数:每次移位时,使用变量 num 记录移位的次数。当 leftright 最终相等时,left 就是它们的公共二进制前缀
  4. 还原结果:最后,将公共前缀 left 向左移动 num 位(相当于补 num0),即得到最终按位与的结果。

🔥代码实现(含详细变量注释)

class Solution {
    public int rangeBitwiseAnd(int left, int right) {
        // num:记录 `left` 和 `right` 同时向右移位(除以 2)的次数
        // 这个次数也代表了最终结果需要在公共前缀后面补的 `0` 的个数
        int num = 0;
        
        // 只要 left 小于 right,说明它们的二进制在低位还有差异
        // 需要不断缩小范围,寻找它们的公共高位前缀
        while (left < right) {
            left >>= 1;   // left 除以 2,舍弃最低位
            right >>= 1;  // right 除以 2,舍弃最低位
            num++;        // 记录已经移位的次数
        }
        
        // 循环结束时,left 和 right 相等,即找到了公共前缀
        // 将公共前缀左移 num 位(补上 num 个 0),即为该区间按位与的最终结果
        return left << num;  
    }
}
  • ⏱️复杂度分析
    • 时间复杂度:O(log N)(或视为常数时间 O(1))。循环执行的次数取决于 left 和 right 的最大二进制位数。在 Java 的 int 类型下,最坏情况下循环最多执行 32 次,效率极高。

    • 空间复杂度:O(1),只使用了一个额外的整型变量 num 来记录移位次数

🔍总结一下:

这类题真的很考验数学逻辑:

这道题最本质、最核心的灵魂如下:

假设从数字A到数字B,二者的二进制公共前缀是X,不公共的称为Y,也就是说,你从A到B,不看公共前缀X,A的不公共的Y部分一定经历了从0到1和从1到0的变化,才能成为B

image-nkEc.png