LeetCode260. 只出现一次的数字 III

力扣题目链接:https://leetcode.cn/problems/single-number-iii/description/

题目叙述:

给你一个整数数组 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]

提示:

2 <= nums.length <= 3 * 10^4
-2^31 <= nums[i] <= 2^31 - 1
除两个只出现一次的整数外,nums 中的其他数字都出现两次

思路

  1. 这题我们仍然可以采用异或运算的性质来解决,通过LeetCode136题,我们了解了异或运算的性质,在这里我们当然也可以去用异或运算来解决这道题目

  2. 由题目可知,有两个数字(假设位x,y)只出现了一次,那么我们对数组中的所有元素做异或操作,得到的结果k的值是x^y。并且k的值一定不为0(因为x!=y),所以k必然有一位数字位1,那么x,y的第n
    位一定有一个是1,有一个是0,这样它们异或的结果在第n位才有可能是1。这里假设数字x的第n位位1,数字y的第n位为0

  3. 那么我们想要求出x,y。怎么做呢?我们可以提取出k的最右侧的1,让k1=k&-k(这样就可以提取出k的最右侧的1),然后进行分组,我们可以将这个数组分为两组,一组它的第n为是1,与x一组,一组它的第n为是0,与y一组,那么我们对这两组的数字分别进行异或运算,我们得到的两个答案一定分别是x和y。(因为这两组中除了x,y,其他的元素都是成对出现的)

  4. 那么我们怎么实现分组呢?---可以对数组中的元素进行位与&运算,如果得到的结果为0的话,证明这个数字第n为肯定为0(与y一组),如果结果不为0,那么这个数字的第n为一定是1(与x一组),最后分别对x组,y组中的元素做异或运算,就可以得到结果了。

最后,附上C++参考代码

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int k=0;
        //假设这两个单个出现的数字分别为X,Y
        //对这个数组中所有的元素进行异或运算,得到的结果肯定是X^Y
        for(auto & it:nums) k^=it;
        //提取出k最右边的1,假设这是第n位
        int k1=k&-k;
        //定义x,y,假设这两个数字是只出现一次的那两个数字
        int x=0,y=0;
        //遍历数组,将数组分为两组
        for(int num:nums){
            //如果位与&运算的结果不为0,那么与x一组
            if((num&k1)!=0) x^=num;
            //否则与y一组
            else y^=num;
        }
        //得到的x,y就是我们要求的结果
        return {x,y};
    }
};
posted @ 2024-07-23 10:51  Tomorrowland_D  阅读(3)  评论(0编辑  收藏  举报