260. Single Number III

Source: https://leetcode.com/problems/single-number-iii/

Description:

Given an array of numbers nums, in which exactly two elements appear only once and all the other elements appear exactly twice. Find the two elements that appear only once.

Example:

Input: [1,2,1,3,2,5]
Output: [3,5]

Note:
The order of the result is not important. So in the above example, [5, 3] is also correct.
Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?

图片来源:https://leetcode-cn.com/problems/single-number-iii/solution/zhi-chu-xian-yi-ci-de-shu-zi-iii-by-leetcode/
(图片来源:https://leetcode-cn.com/problems/single-number-iii/solution/zhi-chu-xian-yi-ci-de-shu-zi-iii-by-leetcode/)

最直接的办法是遍历数组,用一个map记录数字出现次数,最后再遍历map,把出现一次的找出来。时间和空间复杂度都是线性的。

代码:

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        map<int,int> cnt;
        int n=nums.size();
        for(int i=0;i<n;i++){
            if(cnt.find(nums[i])==cnt.end()){
                cnt[nums[i]]=1;
            }
            else{
                cnt[nums[i]]++;
            }
        }
        vector<int> ans;
        for(map<int,int>::iterator it=cnt.begin();it!=cnt.end();it++){
            if(it->second==1)
                ans.push_back(it->first);
        }
        return ans;
    }
    
};

巧妙方法:bitmask

经典的一个问题是这样的,题设与本题基本相同,唯一不同的是有且仅有一个数字出现过一次而其他数字都出现过两次。最优解法是把所有数字做异或,这样出现过两次的数字在异或结果中就会消失,只有那个出现一次的数字的所有bit会保留,就是最终的异或结果。

这里同样把所有数字做异或,但是最终得到的结果是两个仅出现一次的数字(记为a和b)的异或结果。那如何把它们分开呢?

x&(-x)可以取出x中最右边一位的1

-x其实是x按位取反再加一

i. if x最后一位是1,取反0,加1为1,&为1;除最后一位外,前面所有位刚好全是反的,&为0,。ok
ii. if x最后一位不是1,是0,取反1,加1变0并进位,现在假设按位取反后从最低位开始有若干位1 然后才是0,那么在加一的过程中,这些1都变成0,第一个0变成1,再往前就都不变了。然后再&,就把第一个0变成1那一位弄出来了。过程如下

cccc…10…0 (x)
| 取反
dddd…01…1 (~x)
| +1
dddd…10…0 (-x)
| 求&
0000…10…0 (-x&x)

于是把a^b异或结果x进行上述操作取出最右边的一个1,这一位是1就表明a和b在这一位是不同的,那么原先数组中所有出现过两次的数字,在这一位要么是1,要么是0,意味着它们可以被分为a组和b组,分组后做异或,相当于把问题转化为仅有一个出现一次的数字的问题了。实现上,就把x&(-x)的结果与数组中数字做&,看看结果是不是0就行了。

另外,异或还有一个特点是

x^y=t

若已知x和t,那么y=x^t.

代码:

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        
        int Xor=0;
        int n=nums.size();
        for(int i=0;i<n;i++){
            Xor^=nums[i];
        }
        
        int tmp=Xor&(-Xor);
        vector<int> ans(2);
        int x=0;
        for(int i=0;i<n;i++){
            if((nums[i]&tmp)==0){
                x^=nums[i]; //分组做xor
            }
        }
        ans[0]=x;
        ans[1]=x^Xor;
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值