Single Number III

25 篇文章 0 订阅

原题

原题

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.

For example:

Given nums = [1, 2, 1, 3, 2, 5], return [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?

思路 (参考)

跟 Single Number(https://leetcode.com/problems/single-number/) 类似的情况: 
相同的数字是偶数个,
不同的是, 这里面有两个不同的只出现一次的元素. 
很容易联想到Single Number的解法, 
把所有数异或起来(即或之后我们得到的是我们想要的那两个数的异或值), 
然后把它们从异或中拆分开. 那么怎么拆分出来?

假设我们要找的这两个数为 a, b, 而x = a ^ b. 
首先a 肯定不等于 b, 说明它们的二进制位一定是不完全相同的, 
所以x肯定不为 0.
也就是说a与b一定存在"某个bit", 
使得在它们中的某个数中是0, 而在另一个数中是1, 
这是他们之间的一个差别.
我们可不可以利用这个差别来把这两个数从x中揪出来呢? 
是可以的.

利用这个差别, 我们可以将整个 nums 集合分成两个集合.
一个集合中是这"某个bit"0的在nums中的所有数, 
假设为集合A.而另一个集合是这"某个bit"为为1的在nums中的所有数.
假设a的这"某个bit"0 , b的"某个bit"1, 
那么显然a在集合A中, b在集合B中, 
另外显然A中的元素除了a之外, 每个不同的元素都是出现2次的, 
同理B也是. 
**************
(想想为什么?)
**************
这样问题就完全转化成了与Single Number一样的两个子问题, 
于是该问题可解.

关于具体的代码实现, 还有一点说明:
我们如何找到这个"某个bit"呢? 
理论上, 只要是在这一位上a与b的值不同, 都可以合格的成为我们需要找的某一位. 
既然无更多限制, 那我们肯定是找好找的某一位咯, 如most-right set bit. 
most-right set bit可以通过以下方式获得 x & (-x). 这里就不展开说了. 
(ps: n & (n - 1)是消去n的most-right set bit)

code

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        if(nums.size() == 2) return nums;
        vector<int>res;

        // a == (0 ^ a)
        // 0 == (a ^ a)
        int x = 0;
        int len = nums.size();
        for(int i = 0; i < len; i++) {
            x ^= nums[i];
        }

        // if a and b that we want are the two distinct numbers in nums,
        // so x = a ^ b, and x != 0.
        // so there must be at least an set bit (that is, the bit with value '1') of the xor value x,
        // what we do is to find a set bit, like the most right set bit. (why?)
        // we use the set bit to construct an integer y (the bits of y are all '0', except one '1')
        // then we use y to split nums into two groups A and B, on the condition of nums = A `union` B
        // and A `interset` B is empty set.
        // a and b are distinctly distributed into the A and B. (means `a in A and b in B` or `a in B and b in A`)
        // both A and B satisify:
        //  one elements appear only once and all the other elements appear exactly twice.
        // here we don't care about the number of A or B

        int a = 0;
        int b = 0;
        // 
        int y = x & (-x);
        for(int i = 0; i < len; i++) {
            // use set bit to distinct a and b, and other elements in nums.
            // that is, grouping nums
            if(nums[i] & y) a ^= nums[i];
            else b ^= nums[i];
        }

        res.push_back(a);
        res.push_back(b);
        return res;

    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值