LeetCode Single Number II

LeetCode解题之Single Number II


原题

一组数字中,有一个数字只出现一次,其余的都出现了三次,找出只出现了一次的那个数字。

注意点:

  • 线性时间复杂度
  • 最好不用额外申请空间

例子:

输入: nums = [1, 1, 1, 2, 3, 3, 3]

输出: 2

解题思路

如果要不额外申请空间,可以通过三个变量来记录每位出现的次数,注意顺序上应该先算出现三次、两次,再一次的,如果反过来的话会出现重复计算(如计算第一个数字时,one = one | num -> num,two = two | one & num -> num,three = two & num -> num,而此时显然不应该存在有位已经出现两次或三次)。当一个位的出现次数已经到三次了,那么就将这些位抹去。最后剩下的就是那个只出现一次的数。

上面的方法不是很通用,如果除一个数字外其余的数字出现了n次,那上面的方法就不容易解决了。可以用了一个包含32个元素(因为int型数值为32位)的数组来记录每一个位出现的次数,最后对每位对n进行取余操作,并通过位移操作将剩余的数字拼起来。对于Python需要注意的是要考虑负数的情况,因为Python默认数值都是可以无限大的,而不是根据首位是否为0来区分正负数,需要手动分辨一下。

AC源码

class Solution(object):
    def singleNumber(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        one, two, three = 0, 0, 0
        for num in nums:
            # calculate the count of the each bit
            three = two & num
            two = two | one & num
            one = one | num
            # clear the count for the bit which has achieved three
            one = one & ~three
            two = two & ~three
        return one

    def singleNumber_normal(self, nums):
        result = 0
        for i in range(32):
            count = 0
            for num in nums:
                count += (num >> i) & 1
            rem = count % 3
            # deal with the negative situation
            if i == 31 and rem:
                result -= 1 << 31
            else:
                result |= rem << i
        return result


if __name__ == "__main__":
    assert Solution().singleNumber([1, 1, 1, 2, 3, 3, 3]) == 2
    assert Solution().singleNumber([-2, -2, 1, 1, -3, 1, -3, -3, -4, -2]) == -4
    assert Solution().singleNumber_normal([1, 1, 1, 2, 3, 3, 3]) == 2
    assert Solution().singleNumber_normal([-2, -2, 1, 1, -3, 1, -3, -3, -4, -2]) == -4

欢迎查看我的Github (https://github.com/gavinfish/LeetCode-Python) 来获得相关源码。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值