Day22:位运算

剑指 Offer 56 - I. 数组中数字出现的次数

题目分析

  1. 学习了异或的性质。1.恒等律:X ⊕ 0 = X 2.归零律:X ⊕ X = 0 3.交换律A ⊕ B =B ⊕ A
    4.结合律分配律也都满足。
  2. 回到题目上,简化问题,如果只有一个只出现过一次的数字,那么我们完全可以通过异或的性质来解决题目,初始化x=0,x去异或数组里面的每个数,出现过两次的数字会变成0,而且这跟数字的顺序没有关系,因为交换律在此做了支撑。所以最后x会直接 = 那个只出现过一次的数字。可惜题目中说有两个只出现过一次的数,那么情况就需要再分析分析。
  3. 首先我们第一次异或整个数组,因为出现过两次的数字全部会变成0,剩下的就是我们值出现过一次的两个数字异或的结果 Z = X ⊕ Y,这个结果是什么呢?XY是两个不一样的数字,所以至少有一位上,他们是不相同的,也就是分别为0,1。所以根据异或的性质,在这一位上,异或的结果Z是为1的。我们可以根据这一位的不同将原来一个数组分为两个数组,这样两个数组分别异或返回结果就解决问题了。重点是怎么根据这一位的不同将一个数组分为两个数组。
    在这里插入图片描述
    将Z与m做与运算,只有与到Z中第一位的(从右到左)1时与运算结果才不为0,否则其他情况下m左移一位。这样我们就得到了一个m.它除了那个位上为1外其他都为0,然后根据与这个M做与运算的结果可以将数组分为两个。
class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int x = 0, y = 0, n = 0, m = 1;
        for(int num : nums)         // 1. 遍历异或
            n ^= num;
        while((n & m) == 0)         // 2. 循环左移,计算 m
            m <<= 1;
        for(int num : nums) {       // 3. 遍历 nums 分组
            if(num & m) x ^= num;   // 4. 当 num & m != 0
            else y ^= num;          // 4. 当 num & m == 0
        }
        return vector<int> {x, y};  // 5. 返回出现一次的数字
    }
};

剑指 Offer 56 - II. 数组中数字出现的次数 II

Difficult,状态级太难了,直接hash。
Leetcode: https://leetcode-cn.com/leetbook/read/illustration-of-algorithm/9hyq1r/.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值