leetcode位运算学习笔记——只出现一次的数字

只出现一次的数字系列(位运算题解)

136. 只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素(使用常数空间)。

思路:

1、结合律:(a ^ b) ^ c = a ^ (b ^ c)

2、对于任何数x,都有x ^ x = 0,x ^ 0 = x
初始化一个元素a=0,与所有元素做一次异或,即可得到只出现一次的元素

代码:

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        a = 0
        for num in nums:
            a ^= num
        return a

137. 只出现一次的数字 II

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。(使用常数空间)

思路:

基本思路还是借助异或运算来消除相同元素,但是由于每个元素出现了三次,需要另外借助一个变量b。
数组中的数字出现的次数为1或3;为了找出出现一次的数字,出现三次的数字异或运算之后,结果必须为0,出现一次的数字经过异或运算之后结果是他本身。用代码表示:

if b == 0:
  if n == 0:
    a= a
  if n == 1:
    a= ~a
if b== 1:
    a= 0

代码:

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        a, b = 0, 0
        for num in nums:
            a = a ^ num & ~b
            b = b ^ num & ~a
        return a

260. 只出现一次的数字 III

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。(使用常数空间)。

思路:

和136题的区别在于这个数组有两个只出现一次的数,所以可以借鉴。关键就是把数组分成两个部分,每个部分包含一个只出现一次的数字。
那么怎么把数组分成两部分呢?
这里数组所有元素都做一次异或运算的话,得到的结果是两个只出现一次的数字的异或结果s。要把这两个数字分开,可以在s的二进制表示中找到一个1,因为异或相同为0,相异为1,意味着这两个只出现一次的数的二进制表示是不同的,根据这个就可以把数组分成两个部分,至于其他出现两次的数,也按照这个规则分成两拨,不会影响结果。
那么,怎么找到异或结果中的1呢?
这里使用了s&(-s)得到二进制数s最低位的1,其他位置零.至于为啥是这样(我也是看了其他题解的,反正我想不到)
得到划分数组的那个数之后,遍历数组,把其中一类做异或运算得到的结果就是一个只出现一次的数;再把它和两个只出现一次的数 的异或结果(就是原数组元素的异或结果)做一次异或运算,根据异或运算的结合律,可以得到另一个只出现一次的数。

代码:

class Solution:
    def singleNumber(self, nums: List[int]) -> List[int]:
        a = 0
        for num in nums:
            a ^= num
        diff = a & (-a)  # 保留二进制数a最低位的1
        b = 0
        for num in nums:
            if diff & num:  # 相当于把原数组分组
                b ^= num
        return [b, b^a]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值