260. 只出现一次的数字 III

253 阅读2分钟

260. 只出现一次的数字 III

「这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

给定一个整数数组 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 * 104
  • -231 <= nums[i] <= 231 - 1
  • 除两个只出现一次的整数外,nums 中的其他数字都出现两次

解题思路

哈希表

  1. 用哈希表unordered_set存储表内从未有过的数字
  2. 遍历数组,若哈希表内有此数字num,则在哈希表内删除num,否则将num写入哈希表
  3. 返回最终剩余的哈希表内的数字

代码

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
    unordered_set<int> ansSet;
    for(auto &x:nums){
        if(ansSet.find(x)!=ansSet.end()){//判断数字是否重复
            ansSet.erase(x);//重复则删除
        }else {
            ansSet.insert(x);//不重复写入
        }
    }
    return {ansSet.begin(),ansSet.end()};
    }
};

位运算

前导知识:两个相同的数异或是零,多个数异或只要出现两个数相同,则异或结果就是把这两个数去掉剩下的数异或,即1^2^3^4^5^6^1^2==3^4^5^6

  1. 把数组内每一个数字num异或得到两个仅出现一次的数字的异或值TwoNumsXor
  2. 这两个数字至少有一位是不同的,并且其中一个ansNum1该位为0(1),另一位ansNum2该位为1(0)
  3. 找出最低位不同的方法是TwoNumsXor&-TwoNumsXor,-TwoNumsXorTwoNumsXor取反加1,二者异或肯定会得到一位且仅剩这位数字为1,说明TwoNumsXor本身该位就是1,10^1得来,说明了第2条的观点
  4. 每个数num分别与Classification进行与操作即可分类,出现两次的数字肯定会分到一组,用结果ansNum异或此时的num最终即可得到该数字

代码

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int TwoNumsXor=0;
        for(auto &num:nums){
            TwoNumsXor^=num;
        }
        int Classification=TwoNumsXor==INT_MIN?TwoNumsXor:TwoNumsXor&-TwoNumsXor;
        int ansNum1=0;
        int ansNum2=0;
        for(auto &num:nums){
            if(num&Classification){
                ansNum1^=num;
            }else {
                ansNum2^=num;
            }
        }
        return {ansNum1,ansNum2};
    }
};

😝最近新创建了个开源仓库,总结LeetCode的每日一题,目前已有C++、JavaScript和部分Java、Python语言版本,欢迎大家完善补充! 🖥️仓库地址:每日一题系列