JZ40 数组中只出现一次的数字

描述

一个整型数组里除了两个数字只出现一次,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

这题用上之前说的python内置函数就是我能写出来的代码了:

class Solution:
    def FindNumsAppearOnce(self , array ):
        if array == []:
            return False
        else:
            tmp = []
            for i in range(len(array)):
                if array.count(array[i]) == 1:
                    tmp.append(array[i])
            return tmp

但是这道题又说清楚了只有两个数字出现一次,其他数字都出现了两次,这会不会另有玄机?

果然,讨论组又是另外一个知识点:

①如果只有一个数字仅出现一次,其余都出现两次,则所有数字异或的结果就是那个仅出现一次的数字。

什么是异或?

异或(eor)是一个数学运算符。它应用于逻辑运算。异或的数学符号为“⊕”,计算机符号为“eor”。

 a \oplus b = (\lnot a\wedge b) \vee (a\wedge \lnot b)

 如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。

结合律:a \oplus b \oplus c =a \oplus c \oplus b

如果该数组中只有一个数字出现一次,就把全部数字异或,就能找到那个数。

对于有异或的题目要记住这点 每个二进制位是独立计算答案的

②讨论组题解:此题中,有两个数字只出现一次,它们与其他所有数字异或的结果一定非0,其二进制表示中一定有某一位为1,可根据这一位是否为1,将数组分为两部分。

利用二进制的第一位为1来区分两个数组,如果第一位不是1,那就判断第二位,第三位,一直到找到为1的地方。假设一直找到第n位才为1,那就判断数组中的其他数字的二进制的第n位是否为1,做&运算即可判断。

&(与)运算定义:参加运算的两个数据,按二进制位进行“与”运算。

运算规则:0&0=0 0&1=0 1&0=0 1&1=1

则两部分的所有数字分别做异或,因为异或的运算规则是可以符合结合律的,所以一旦出现两个相同的数,它们的异或结果就是0,那么那个只出现一次的数跟它们做异或的结果就是这个数本身,两部分得到的两个结果就是要求的两个结果。

class Solution:
    def FindNumsAppearOnce(self , array ):
        # write code here
        if not array:
            return []
        res = 0
        for i in array:
            res = res ^ i
        index = 0
        while res & 1 == 0:
            res = res >> 1
            index += 1
        a, b = 0, 0
        for i in array:
            if self.helper(i, index):
                a = a ^ i
            else:
                b = b ^ i
        return [a, b] if a < b else [b, a]
    
    def helper(self, num, index):
        num = num >> index
        return num & 1 != 0

③姚青林老师的方法也很类似:

因为两个数字只出现一次,等于说把两个数字分成两边,让每一边只有一个数字只出现一次,然后取做异或。

class Solution:
    def FindNumsAppearOnce(self , array ):
        if len(array) < 2:
            return None
        twoNumXor = None
        for num in array:
            if twoNumXor == None:
                twoNumXor = num
            else:
                twoNumXor = twoNumXor ^ num
        count = 0
        while twoNumXor % 2 == 0:
            twoNumXor = twoNumXor >> 1
            count += 1
        mask = 1 << count
        firstNum = None
        secondNum = None
        for num in array:
            if mask & num == 0:
                if firstNum == None:
                    firstNum = num
                else:
                    firstNum = firstNum ^ num
            else:
                if secondNum == None:
                    secondNum =num
                else:
                    secondNum = secondNum ^ num
        return firstNum, secondNum

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值