leetcode-260.只出现一次的数字 III

位运算


题目详情

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。
进阶:你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?


示例1:

输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。

示例2:

输入:nums = [-1,0]
输出:[-1,0]

示例3:

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

方法一 哈希

利用哈希map存储每个数字的次数,最后统计即可

我的代码:

class Solution 
{
public:
    vector<int> singleNumber(vector<int>& nums) 
    {
       unordered_map<int, int> map;
       for (int num : nums)
       {
           ++map[num];
       }
       vector<int> ans;
       for (const auto& [num, cishu]: map)
       {
           if (cishu == 1)
           {
               ans.push_back(num);
           }
       }
       return ans;
    }
};

方法二 简化问题 异或运算

leetcode-136.只出现一次的数字 中,只有一个不同的数字,那么我们通过异或的方法最后留下来的就是答案,那么这道题如果我们仍然异或下来,那么最后留下的是两个答案的异或值(假设答案是a,b,最后留下的就是a ^ b),那么该咋办呢?哎呀!如果我们可以把a和b分开到两个数组里分别处理就好了
我们可以知道,a ^ b就是将a和b的二进制每一位异或运算,当二者相同时就会得到0,否则就是1
则我们可以像leetcode-136.只出现一次的数字 一样,先将所有数字异或运算,最后得到a ^ b
然后找到这个结果的二进制中的某一个是1的位置,这个点就是分离a和b的关键
我们找到这个位置之后,将原来的所有数中该位置是0的分为一组,该位置是1的分为一组
我们再分别利用异或处理这两组,即可得到答案
我们可以很方便的用x & -x 得到倒数第一位是1的数,但是要注意溢出问题
因为若x = MIN_INT = -2147483648 则-x就是2147483648就会溢出(正数的最大值是2147483647)
我们需要做些处理

class Solution 
{
public:
    vector<int> singleNumber(vector<int>& nums) 
    {
       int allxorsum = 0;
       for (int num : nums) // 将所有数异或
       {
           allxorsum ^= num;
       }
       // 防止溢出
       int lsb = (allxorsum == INT_MIN ? allxorsum : allxorsum & (-allxorsum));
       int ty1 = 0, ty2 = 0;
       for (int num : nums)
       {
           if (num & lsb) // 对应位是1的归为一类进行异或运算
           ty1 ^= num;
           else           // 对应位是0的归为一类进行异或运算
           ty2 ^= num;
       }
       return {ty1, ty2};
    }
};

位运算常用技巧

位运算常用技巧

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ggaoda

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值