201. 数字范围按位与

给定范围 [m, n],其中 0 <= m <= n <= 2147483647,返回此范围内所有数字的按位与(包含 m, n 两端点)。

示例 1:

输入: [5,7]
输出: 4
示例 2:

输入: [0,1]
输出: 0

方法一:位移
思路

鉴于上述问题的陈述,我们的目的是求出两个给定数字的二进制字符串的公共前缀,这里给出的第一个方法是采用位移操作。

我们的想法是将两个数字不断向右移动,直到数字相等,即数字被缩减为它们的公共前缀。然后,通过将公共前缀向左移动,将零添加到公共前缀的右边以获得最终结果。

在这里插入图片描述
算法

如上述所说,算法由两个步骤组成:

我们通过右移,将两个数字压缩为它们的公共前缀。在迭代过程中,我们计算执行的右移操作数。
将得到的公共前缀左移相同的操作数得到结果。

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 算法
思路与算法

还有一个位移相关的算法叫做「Brian Kernighan 算法」,它用于清除二进制串中最右边的 11。

Brian Kernighan 算法的关键在于我们每次对 \textit{number}number 和 \textit{number}-1number−1 之间进行按位与运算后,\textit{number}number 中最右边的 11 会被抹去变成 00。

在这里插入图片描述
基于上述技巧,我们可以用它来计算两个二进制字符串的公共前缀。

其思想是,对于给定的范围 [m,n][m,n](m<nm<n),我们可以对数字 nn 迭代地应用上述技巧,清除最右边的 11,直到它小于或等于 mm,此时非公共前缀部分的 11 均被消去。因此最后我们返回 n 即可
在这里插入图片描述
在上图所示的示例(m=9, n=12m=9,n=12)中,公共前缀是 0000100001。在对数字 nn 应用 Brian Kernighan 算法后,后面三位都将变为零,最后我们返回 nn 即可。

class Solution {
    public int rangeBitwiseAnd(int m, int n) {
        while (m < n) {
            // 抹去最右边的 1
            n = n & (n - 1);
        }
        return n;
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值