[leetcode] 1608 面试题56-I 数组中数字出现的次数(分组异或)

问题描述

一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。

示例

示例1

输入:nums = [4,1,4,6]
输出:[1,6] 或 [6,1]

示例2

输入:nums = [1,2,10,4,1,4,3,3]
输出:[2,10] 或 [10,2]

限制

2 <= nums <= 10000

解题思路

这个题难在空间复杂度要达到O(1),这意味着我们不能使用另外一个数组来做(不然也太简单了)。看了题解后才会做的,我位运算练习的太少了。

首先我们考虑如果是一个数字只出现了一次,我们应该怎么做?自然是异或,从头异或到尾,结果就是那个数字。这是因为相同的数字异或会抵消掉。

那么两个数字呢,假设两个数字是a和b,最终结果是c,那么将c化为二进制就是 c x c x 1 c 2 c 1 c 0 c_xc_{x-1} \cdots c_2c_1c_0 ,每一位都是对应a和b的异或值,关键就在于分组,将a与b分到两组中,并且其他的数据每一对都分到同一组中。

假设 c k = = 1 c_k==1 ,那么我们知道 a k b k a_k\ne b_k ,假设任选一个数据为x,那么我们可以当 x k = = 1 x_k==1 的时候,放到一组, x k = = 0 x_k==0 的时候,放到另一组,这样每一对都放在一组里面了,同时保证了a和b不在同一个组中(因为当前位置 a k b k a_k\ne b_k )。

完整代码

class Solution {
public:
    vector<int> singleNumbers(vector<int>& nums) {
        int a=0,b=0,c=0,pos=1;
        for (auto i:nums) c^=i;
        while(!(pos&c)) pos<<=1;//找到从右边起第一个非0的位置
        for (auto i:nums){
            if(pos&i) a^=i;
            else b^=i;
        }
        return vector<int>{a,b};
    }
};
原创文章 61 获赞 58 访问量 6476

猜你喜欢

转载自blog.csdn.net/weixin_43347376/article/details/105805618