剑指Offer 56| LeetCode 136.只出现一次的数字(Python)

LeetCode 136.只出现一次的数字
剑指Offer 56.数组中只出现一次的数字


LeetCode 136.只出现一次的数字

给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。
说明:
算法应该具有线性时间复杂度。 要求不使用额外空间来实现。

输入:[2,2,1]
输出:1
输入:[4,1,2,1,2]
输出:4

解题思路
哈希表

以元素值为key,元素出现的频次为value,构建字典,最后返回value == 1的key即可。
这个方法最大的缺点在于占用了O(n)的辅助空间,因此不满足题目要求。

class Solution:
    def singleNumber(self, nums: List[int]) -> int:
        dic = {}
        for i in range(len(nums)):
            if nums[i] not in dic:
                dic[nums[i]] = 1
            else:
                dic[nums[i]] += 1
        for key, value in dic.items():
            if value == 1:
                return key
        return None

位运算(异或)

利用位运算解决此题是较优的做法。
异或运算满足以下三个定律:

  • 交换律:a ^ b ^ c <=> a ^ c ^ b
  • 任何数于0异或为任何数 0 ^ n => n
  • 相同的数异或为0: n ^ n => 0

因此在题例中,4 ^ 1 ^ 2 ^ 1 ^ 2 = 1 ^ 1 ^ 2 ^ 2 ^ 4 = 0 ^ 2 ^ 2 ^ 4 = 0 ^ 0 ^ 4 = 4

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

剑指Offer 56.数组中只出现一次的数字

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


解题思路

与上题不同,上题只有一个数字出现一次,而这题是有两个数字出现一次。
继续考虑用位运算来处理,核心思想是将数组分为两半再进行上题的操作

  • 和上题一样,先将所有的数字进行异或,最后肯定得到两个只出现一次的数字异或的结果;
  • 对这个结果进行分析,找到其二进制为1的最低位,这个位上为1,说明两个数字的二进制在这个位上不相同,必然一个为1,一个为0;
  • 可以根据在此位上是否1,将数组里的所有数分为两半,每边都为若干对成对的数字加上一个只出现一次的数字;
  • 最后在两边各自按上题异或即可。
class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字

	# 判断此位上是否为1
    def isBit(self, num, index):
        num >>= index
        return num & 1
    
    def FindNumsAppearOnce(self, array):
        # write code here
            if not array: return 
    
            temp = 0
            for num in array:
                temp ^= num

            # 没有只出现一次的数字
            if temp == 0: return

            index = 0
          	# 找到为1的最低位
            while (temp&1) == 0:
                temp >>= 1
                index += 1

            a = b = 0
            # 分为两半,进行异或
            for num in array:
                if self.isBit(num, index):
                    a ^= num
                else:
                    b ^= num

            return [a,b]

2019.7.15 补充剑指Offer部分

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值