260. Single Number III

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.

Example:

Input: [1,2,1,3,2,5]
Output: [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?

方法1:

水中的鱼:http://fisherlei.blogspot.com/2015/10/leetcode-single-number-iii-solution.html

思路:

这题有两个未知数,直接做异或肯定是不行的,那么如何通过一些变换把这道题分解开,使得可以应用Single Number的解法来做,才是这个题目有意思的地方。
首先,对于数组A, 假设存在b,c两个数字,在数组中只出现了一次,那么对于整个数组进行异或操作的话,
^ [A] = b^c , 因为其他的数因为出现了两次,异或的过程中就被清零了。

但是仅仅通过最后异或出来的值,是没办法求出b和c的值的,但是足以帮我们把b和c划分到不同的子数组中去。

一个整数有32位bit,对于b和c,除非两者是相同的数,否则一定存在第K位bit,两者是不同的。看下面的例子,
在这里插入图片描述
当找到这个K以后,就可以按照第K位bit是否等于1,将A数组划分成两个子数组,而这两个子数组分别包含了b和c,那么剩下的就只需要把single number的算法直接应用到这两个子数组上,就可以得到b和c了。

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int num = 0;
        for (int a: nums) num ^= a;
        int i = 0;
        for (; i < 32; i++) {
            if (num & (1 << i)) break;
        }
        int a = 0, b = 0;
        for (int num: nums) {
            if (num & (1 << i)) a ^= num;
            else b ^= num;
        }
        return {a, b};
    }
};

grandyang: https://www.cnblogs.com/grandyang/p/4741122.html

进行 a &= -a 操作。首先变负数吧,在二进制中负数采用补码的形式,而补码就是反码 +1,那么 110 的反码是 11…1001,那么加1后是 11…1010,然后和 110 相与,得到了 10,就是代码中的 diff 变量。

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int diff = accumulate(nums.begin(), nums.end(), 0, bit_xor<int>());
        diff &= -diff;
        vector<int> res(2, 0);
        for (auto &a : nums) {
            if (a & diff) res[0] ^= a;
            else res[1] ^= a;
        }
        return res;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值