LeetCode260:Single Number III 只出现一次的数字III

LeetCode260:Single Number III 只出现一次的数字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:

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?

分析

由于做过之前的简单类型的题目,所以知道可以考虑二进制的运算,但是约束条件有两个条件出现一次使得题目难度上升了一个层次。最后参考了评论里面用python写的代码,以及其他博客的分析,大致整理出一下。
首先双双成对的我们是可以通过异或操作(异1同0)全部变成0搞掉,所以要考虑怎么把不同的两个数给区分开。
按照题目的例子来: [1,2,1,3,2,5],我们要将3和5给残忍地隔开,方法就是首先
【1】将所有的树累加求异或,异或满足交换律和结合律,那么我们累加求异或等价于将3和5异或,也即011^101=110。然后
【2】和其负数(二进制表示为反码+1,也即补码。000…110------->111…001+1------->111…010)作与操作,即110&010=010(有零为零)。那么我们看1的位置,就是区分

3(011)
5(101)

从右往左数第一个不同的位置。

为什么要和负数作与操作呢?

首先我们3和5相与后得到110知道前2位数字不同,但是为了得到最后可以执行选择判断语句if(为1/0),我们需要将最低位的1前面的所有1变成0,这样在后面和3/5相与的时候,除了从右往左数第二位,其他全部为0。而第二位3和5不一样(1/0),因此和“1”相与后必定得到一个为0,另一个非零。

这样,我们再写一段代码,让原来的数组里的数分别和010相与,相同的数字会被仍到同一数组内,并在异或运算中抵消到,不管它什么时候进去,因为有交换律。
而我们的不同的数字3和5分别和010相与后就会被成功拆散了。
明天情人节呀?愿天下有情人没有这个divi~

C++代码

class Solution {
public:
    vector<int> singleNumber(vector<int>& nums) {
        int divi = 0;
        for(auto &a : nums) {
            divi ^= a;
        }
        divi &= -divi ;
        vector<int> res(2, 0);
        for (auto &a : nums) {
            if (a & divi ) res[0] ^= a;
            else res[1] ^= a;
        }
        return res;
    }
};

python代码

https://leetcode-cn.com/problems/single-number-iii/comments/

class Solution(object):
    def singleNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: List[int]
        """
        acc = 0
        for i in nums:
            acc ^=i
        n = len(bin(acc))-3
        a,b=0,0
        for i in nums:
            if i>>n&1:
                a^=i
            else:
                b^=i
        return b,a
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值