数字范围按位与

题目描述

给定一个范围[m, n] 0 <= m, n <= 2147483647,返回此闭区间内的所有数字进行与运算后的结果。

这是一道leetcode上的经典题目,下面我将介绍两种解法,当然有兴趣的可以去原网站看一下具体题目和官方解答。

常规解法

这种解法是最简单的,包括我一开始也是这样做的。

具体代码如下:

class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        int ans = m;
        for (int i = m; i <= n; ++i)
            ans = ans & i;
        return ans;
    }
};

时间复杂度为O(N),leetcode的编译器是通不过这个复杂度的。何况题目难度为medium,题目要求肯定不会让我们这么。

另外,如果有不了解位运算的,可以看一下我的另一篇博客《位运算知识点总结》

解法一

我们先观察9到12的二进制。

当我们进行与运算的时候,要想成立, 所有位必须为 1 ,反之,如果有一数上的对应位为 0 的话,计算的结果肯定为 0 。再观察上面每一个数的二进制,他们的二进制一定有一个公共前缀(黄色标注)。

这个公共前缀的与运算一定是等于这个公共前缀的。

而任意两个数的与运算,除了公共前缀之外,它的后缀进行与运算的话一定是等于0的,大家不妨拿上笔多试几个数可以发现这个规律。

所以!!这道题由计算它的与运算,转向找到它的公公前缀后就可以得到答案了。

如何计算,在看完代码后,大家一定能够知道。

class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        int ans = 0; // 用来记录左移了几位
        while (m != n) {	
             m >>= 1;
             n >>= 1;
             ans += 1;
        }
        // 还原
        return m << ans;
    }
};

时间复杂度为O(1),因为我们只用了常数级的数据来计算公共前缀

解法二

此解法,我就简单讲一下了,我们在进行计算的时候,实则其实就找到两个数的公共前缀就行了,然后向左移位,就把后缀全部变成0了。

其实还有一种解法,我们可以把二进制最右边的1变成0。

n = n & (n - 1),这个公式就可以把我们一个数的二进制最右边的1变成0,具体可以结合上面的图片思考。

我们参考上面的数据,要计算 9 到 12 的所有数的与运算,其实就是把 12 的 二进制右边的 1 不断的变成 0 ,直到其二进制成为0000 1000,此时肯定比 9 小,那么我们就可以退出循环了,然后将 9 与 0000 1000进行与运算就得到答案了,其实我们不断的把 12 右边第一个 1 变成 0 的过程,就是在求公共前缀。

class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        while (m < n) {	// 当 m = n 或者 大于 n的时候,就说明找到了公共前缀了
            n = n & (n - 1);    // 让n最右边的1变成0
        }
        return n & m;
    }
};

时间复杂度O(1)

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值