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

解题思路

本题有很多种解法,但由于题目进行了限制,因此只能采用位运算的方法才能满足。

异或运算有以下三个性质
在这里插入图片描述
移位运算:>> 每右移1位,相当于除2
与运算:& 判断为奇数还是偶数

对于此题的一个简化版的题目136. 只出现一次的数字
136题可以通过一次遍历的方式直接求解。而本题由于有两个出现的数字,因此如果可以拆分成两个数组,就可以通过136题的方法进行求解。

如果从头到尾依次异或当前的数组的元素,我们的结果将是两个只出现一次的数字异或的结果,由异或的性质可知,两个数相同为0,不同为1,因此可以通过对得到的数字找它第1位为1的位置(从右到左找),并根据这个位置将数组分成两个子数组,再到两个子数组中分别遍历,就可以找到只出现一次的数字。
例如nums = [1,2,10,4,1,4,3,3],2和10是我们的输出,转换为2进制的形式,并进行异或
  2:0010
10:1010
     1000
因此可以发现通过该数字的第3位将数组进行划分

代码

class Solution {
public:
   vector<int> singleNumbers(vector<int>& nums) {
       vector<int> ans;
       if (nums.size() == 0) return ans;
       ans.push_back(0);
       ans.push_back(0);
       int num = 0;
       for (auto e : nums) {//求两个不同数字异或的结果
           num ^= e;
       }
       int indexBit = FindFirstBitIs1(num);
       for (auto e : nums) {//对每个子数组进行异或
           if (isBit1(e, indexBit)) ans[0] ^= e;//子数组1
           else ans[1] ^= e;//子数组2
       }
       return ans;
   }
   unsigned int FindFirstBitIs1(int num) {
       int indexBit = 0;
       while (((num & 1) == 0)) {//和1做与运算,判断是否为1,注意这里的==运算符优先级是高于&,因此要加括号
           num = num >> 1;//右移一位
           indexBit++;
       }
       return indexBit;
   }
   bool isBit1(int num, unsigned int indexBit) {//判断该位是否为1
       num = num >> indexBit;
       return (num & 1);
   }
   
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值