Leetcode 260. Single Number III

28 篇文章 0 订阅
14 篇文章 0 订阅

题目描述:找出一个数组中仅仅出现1次的两个数字,其他数字都出现了2次。

题目链接:Leetcode 260. Single Number III

思路:这个跟第一题 136很相似,只不过这里面有2个出现一次的数字,那题可以用摩尔投票法,也可以用异或相同为0的记录法。
这里就是要找出一个区分位,来区分不同的结果,这个区分就是diff参见下面解释:

这道题是之前那两道 Single Number 和 Single Number II 的再次延伸,说实话,这类位操作Bit Manipulation的题,如果之前没有遇到过类似的题目,楞想是很难相出来的,于是我只能上网搜大神们的解法,发现还真是巧妙啊。这道题其实是很巧妙的利用了 Single Number 的解法,因为那道解法是可以准确的找出只出现了一次的数字,但前提是其他数字必须出现两次才行。而这题有两个数字都只出现了一次,那么我们如果能想办法把原数组分为两个小数组,不相同的两个数字分别在两个小数组中,这样分别调用 Single Number 的解法就可以得到答案。那么如何实现呢,首先我们先把原数组全部异或起来,那么我们会得到一个数字,这个数字是两个不相同的数字异或的结果,我们取出其中任意一位为**‘1’的位,为了方便起见,我们用 a &= -a 来取出最右端为‘1’**的位,具体来说下这个是如何操作的吧。就拿题目中的例子来说,如果我们将其全部亦或起来,我们知道相同的两个数亦或的话为0,那么两个1,两个2,都抵消了,就剩3和5亦或起来,那么就是二进制的11和101亦或,得到110。然后我们进行 a &= -a 操作。首先变负数吧,在二进制中负数采用补码的形式,而补码就是反码+1,那么110的反码是 11…1001,那么加1后是 11…1010,然后和 110 相与,得到了10,就是代码中的diff变量。得到了这个diff,就可以将原数组分为两个数组了。为啥呢,我们想阿,如果两个相同的数字亦或,每位都会是0,而不同的数字亦或,一定会有对应位不同,一个0一个1,这样亦或是1。比如3和5的二进制11和101,如果从低往高看,最开始产生不同的就是第二位,那么我们用第二位来和数组中每个数字相与,根据结果的不同,一定可以把3和5区分开来,而其他的数字由于是成对出现,所以区分开来也是成对的,最终都会亦或成0,不会3和5产生影响。分别将两个小组中的数字都异或起来,就可以得到最终结果了,参见代码如下

代码如下

from functools import reduce
class Solution:
    
    def singleNumber(self, nums: 'List[int]') -> 'List[int]':
        # 异或 看看最后哪两个位是1  异或相同就Wie0 不同为1
        diff = reduce(lambda x,y:x^y,nums)
        diff &= (-diff)  #找到原来那个数从右边起第一个1 其他位在与后置位0 这个就是差异位 因为不同结果为1 
        ans = [0,0]
        for n in nums:
            if (n&diff):  #那一位是1的都会走这个逻辑
                ans[0] ^= n
            else:  #那一位不是1的都不会走这个逻辑 因为最后异或结果就是那样了
                ans[1] ^= n
        return ans                

参考链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值