【LeetCode】位运算做题总结

201. 数字范围按位与

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

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

示例 2
输入: [0,1]
输出: 0

解题思路
比较m和n的前缀,取相同的部分。因为当(m,m+1,…n-1,n)进行连续“与操作”时,会抵消很大一部分,而只剩下m(或n)的前缀部分,最后只需将n归位。
如 5(101) 和 7(111) 结果为 4(100),[12,15] 中 12(1100) 和 15(1111) 结果为 12(1100)。

参考来源
https://blog.csdn.net/smile_watermelon/article/details/47320381

LeetCode提交代码

class Solution {
public:
    int rangeBitwiseAnd(int m, int n) {
        int i;
        for(i=0;m!=n;i++){
            m >>= 1;
            n >>= 1;
        }
        return m<<i;
    }
};

1720. 解码异或后的数组

题目描述
未知整数数组 arr 由 n 个非负整数组成。
经编码后变为长度为 n - 1 的另一个整数数组 encoded ,其中 encoded[i] = arr[i] XOR arr[i + 1] 。例如,arr = [1,0,2,1] 经编码后得到 encoded = [1,2,3] 。
给你编码后的数组 encoded 和原数组 arr 的第一个元素 first(arr[0])。
请解码返回原数组 arr 。可以证明答案存在并且是唯一的。

示例 1
输入:encoded = [1,2,3], first = 1
输出:[1,0,2,1]
解释:若 arr = [1,0,2,1] ,那么 first = 1 且 encoded = [1 XOR 0, 0 XOR 2, 2 XOR 1] = [1,2,3]

示例 2
输入:encoded = [6,2,7,3], first = 4
输出:[4,2,0,7,4]

提示
2 <= n <= 104
encoded.length == n - 1
0 <= encoded[i] <= 105
0 <= first <= 105

解题思路
a ^ b = c,则有a ^ c = b 或 b ^ c = a,

LeetCode提交代码

class Solution {
public:
    vector<int> decode(vector<int>& encoded, int first) {
        int len = encoded.size();
        vector<int> a(len+1); //创建一个新的“数组”
        a[0]={first};

        for(int i=0;i<len;i++){
            a[i+1] = a[i]^encoded[i]; // 此时可直接赋值
        }
        return a;
    }
};

231. 2的幂

题目描述
给定一个整数,编写一个函数来判断它是否是 2 的幂次方。

示例 1
输入: 1
输出: true
解释: 20 = 1

示例 2
输入: 16
输出: true
解释: 24 = 16

示例 3
输入: 218
输出: false

易错点
未考虑n<=0的情况。

LeetCode提交代码

class Solution {
public:
    bool isPowerOfTwo(int n) {
        if(n<=0) return false; // n<=0(易漏)
        else return (n&(n-1))==0; // n>0
    }
};

137. 只出现一次的数字 II

题目描述
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。

说明
你的算法应该具有线性时间复杂度。 你可以不使用额外空间来实现吗?

示例 1
输入: [2,2,3,2]
输出: 3

示例 2
输入: [0,1,0,1,0,1,99]
输出: 99

解题思路
0 ^ x = x,
x ^ x = 0;
x & ~x = 0,
x & ~0 =x;
在这里插入图片描述

LeetCode提交代码

// a为seen_once,b为seen_twice.
class Solution {
public:
    int singleNumber(vector<int>& nums) {
        int a=0,b=0;
        for(int i=0;i<nums.size();i++){
            a = (a^nums[i]) & ~b;
            b = (b^nums[i]) & ~a; 
        }
        return a;
    }
};

260. 只出现一次的数字 III

题目描述
给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。

示例
输入: [1,2,1,3,2,5]
输出: [3,5]

注意
结果输出的顺序并不重要,对于上面的例子, [5, 3] 也是正确答案。
你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

解题思路
题目要求时间复杂度O(N),空间复杂度O(1),可用两个位掩码实现。
bitmask 会保留只出现一次的两个数字(x 和 y)之间的差异。
x & (-x) 是保留位中最右边 1 ,且将其余的 1 设位 0 的方法。
在这里插入图片描述
通过 bitmask & (-bitmask) 保留 bitmask 最右边的 1,这个 1 要么来自 x,要么来自 y。
求得x后,通过 bitmask^x 进而求得y。
注:哈希表时间复杂度O(N),空间复杂度O(N),不符合题目要求。

易错点
测试用例为[1,1,0,-2147483648]时,“~bitmask+1”为-bitmask,为2147483648,超过了int的取值范围“-2147483648 ~ 2147483647”,报错。
故本题需要将bitmask为-2147483648的情况单独处理。

参考来源
https://leetcode-cn.com/problems/single-number-iii/solution/zhi-chu-xian-yi-ci-de-shu-zi-iii-by-leetcode/

LeetCode提交代码

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int bitmask=0; // bitmask为两个出现1次的数中不同的位的二进制数
        for(int i=0;i<nums.size();i++){
            bitmask ^= nums[i];
        }
        int bit;
        if(bitmask==-2147483648) bit = bitmask;
        else bit = bitmask & (~bitmask+1); // bit为bitmask最右边1保留后的二进制数,用于分离两个数
        int x=0;
        for(int i=0;i<nums.size();i++){
            if(nums[i]&bit) // 最右边的1属于nums[i]
                x ^= nums[i]; // 通过^消除其他可能符合的重复数字,最终得到其中一个答案
        }
        return vector<int>{x,x^bitmask};
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值