LeetCode 260:Single Number III

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:

  1. The order of the result is not important. So in the above example, [5, 3] is also correct.
  2. Your algorithm should run in linear runtime complexity. Could you implement it using only constant space complexity?
给定一个整数数组nums,在该数组中只有两个数出现过一次,其余的数都正好出现两次。找到这两个数。

例如:

给定nums = [1, 2, 1, 3, 2, 5],应当返回[3, 5]

注意:

1.结果的顺序并不重要,因此对于上面的例子来说[5, 3]也是正确的。

2.你的算法应该有线性的时间复杂度,你能用静态的内存大小实现吗?(即空间复杂度不依赖输入n)


思路不是特别复杂,排序后顺序扫描一遍,找到与前后均不相同的两个数即可,最后再判断第一个数与最后一个数。其实之前那道找一个数的题我最开始想到的就是这个方法,而这道题再用异或我就想不出来了,因为有两个不一样的数,异或出来的结果不知道要怎么区分。

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        if(nums.size()==2) return nums;
        vector<int> ans;
        sort(nums.begin(),nums.end());
        for(int i=1;i<nums.size()-1;i++)
            if(nums[i]!=nums[i-1]&&nums[i]!=nums[i+1]) ans.push_back(nums[i]);
        if(nums[0]!=nums[1]) ans.push_back(nums[0]);
        if(nums[nums.size()-1]!=nums[nums.size()-2]) ans.push_back(nums[nums.size()-1]);
        return ans;
    }
};

不过在讨论里发现了别人依然用异或做了出来,这里放上大神的思路和代码:

1.assume that A and B are the two elements which we want to find;
2.use XOR for all elements,the result is : r = A^B,we just need to distinguish A from B next step;
3.if we can find a bit '1' in r,then the bit in corresponding position in A and B must be different.We can use {last = r & (~(r-1))} to get the last bit 1 int r;
4.we use last to divide all numbers into two groups,then A and B must fall into the two distrinct groups.XOR elements in eash group,get the A and B.

1.假定我们要找的数字为A和B;

2.异或(XOR)所有的数字,于是我们得到结果 r = A ^ B ,现在我们只需要区分A和B;

3.如果我们在r中能找到'1'比特位(二进制),那么即代表在这个比特位上A和B一定不同(因为只有0 XOR 1 = 1),我们能够用 last = r & (~(r-1)) 来得到r中的最后一个'1'比特位;

4.于是我们可以用 last 来将所有数字分为两组,而A和B一定在两个不同的组中。对每一组都进行异或操作,得到A和B。

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int r = 0, n = nums.size(), i = 0, last = 0;
        vector<int> ret(2, 0);

        for (i = 0; i < n; ++i) 
            r ^= nums[i];

        last = r & (~(r - 1));
        for (i = 0; i < n; ++i)
        {
            if ((last & nums[i]) != 0)
                ret[0] ^= nums[i];
            else
                ret[1] ^= nums[i];
        }

        return ret;
    }
};

(这里开始是我自己写的)整体思路在于如何区分A和B,对于分两组之后A和B落入不同组应该比较好理解(因为数字A和B不同,因此至少会在一位上有不同,而我们就利用该位将整个数组划分为两个组),在之后我们只需要再遍历一次原数组即可,而不需关心其余数字是落入A组还是落入B组。因为相同的数字肯定会落入同一个分组,而在同一个分组中异或两次就消除掉了该数。看完之后不得不说一句牛逼啊~



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值