201. Bitwise AND of Numbers Range

201. 数字范围按位与

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

示例 1: 

输入: [5,7]
输出: 4

示例 2:

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

解法一:

//时间复杂度O(1), 空间复杂度O(1)
class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        int diff = n - m;
        int res = INT_MAX, mask = 1;
        for(int i = 0; i < 31; i++) {
            if(diff >= mask) res &= ~mask;//0
            else res &= (m & n & mask) | ~mask;
            mask <<= 1;
        }
        return res;
    }
};

解法二: 参考题解:使用记二进制1的个数思路求的结果

//时间复杂度O(1), 空间复杂度O(1)
class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        if(m == 0) return 0;
        while(n > m) n &= n - 1;
        return n;
    }
};

解法一:

假设int的二进制位的最低位为第0位,最高符位是第31位,符号位是第32位。

解题核心想法是,对于数字中的任意一位i(0 <= i <= 30),如果m和n之差大于等于2^i,那么在整数序列[m, n]的二进制表示的第i位中,必定至少有一处反转(1转为0或0转为1),那么连续按位与的结果必然是0。例如在序列[5, 6]中,差为1等于2^0,那么从5到6这个过程中,二进制表示的0位必然会反转。

其二是,如果m和n之差小于2^i,那可能反转,也可能不反转。此时取m和n该位的与作为该位的结果(如果反转,那m和n在该位上必然不同)。

解法二:

更简洁的解法。n &= n - 1;这一步的作用是将n最低位的1置0。可以这样理解,从m到n的序列中,这一组数字的二进制位表示可以分为两部分,相同前缀部分和不同的后缀部分(如 1011 0100 和 1011 0110,它们的公有前缀是101101,各自的后缀分别是00、10,也就是说后缀从首个不相同的位开始),区分它们之间大小关系只在于其后缀部分。由于这个序列是连续的整数,所以后缀的首位反转也意味着其后的所有位都有反转,所以后缀取与必然全为0,而前缀又全部相同,所以最后的答案一定是公有前缀 + 后缀等长的0序列,也就是满足 n <= m 时的n。

2020/01/08 23:43
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值