leetcode_260 只出现一次的数字 III

102 阅读3分钟

要求

给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。你可以按 任意顺序 返回答案。

进阶:你的算法应该具有线性时间复杂度。你能否仅使用常数空间复杂度来实现?

示例 1:

输入:nums = [1,2,1,3,2,5]
输出:[3,5]
解释:[5, 3] 也是有效的答案。

示例 2:

输入:nums = [-1,0]
输出:[-1,0]

示例 3:

输入:nums = [0,1]
输出:[1,0]

提示:

  • 2 <= nums.length <= 3 * 104
  • -231 <= nums[i] <= 231 - 1
  • 除两个只出现一次的整数外,nums 中的其他数字都出现两次

核心代码

class Solution:
    def singleNumber(self, nums: List[int]) -> List[int]:
        dic = collections.defaultdict(int)
        for num in nums:
            dic[num] += 1
        return [key for key,val in dic.items() if val == 1]

另一解法

class Solution:
    def singleNumber(self, nums: List[int]) -> List[int]:
        return [key for key,val in collections.Counter(nums).items() if val == 1]

第三种解法

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

image.png

解题思路:第一种解法:我们使用空间换时间的方式,我们使用hash表存储出现次数,最终扫描所有的数据即可得到数据;第二种解法:是第一种解法的简化版本;第三种解法:首先要知道一个数和它本身 XOR的结果是 0;一个数和0 XOR 的结果是它本身。所以如果把整个数组的所有元素都XOR在一起,得到的结果= A ^ B ^ C ^ C ^ D ^ D(假设 A, B是只出现一次的元素, C, D是出现两次的元素) = A ^ B,因为A != B, 所以 A ^ B肯定不是0。令 mask = A ^ B, 然后采用一个特殊的运算:mask = mask & (-mask), 来找到mask不为0 的最后一位,在这一位上,A和B肯定不同,所以这一位才不是0,然后可以利用这个性质,把nums分成两个子数组,分别对应 & mask == 0 和 & mask == 1,然后问题变成了,两个相同的子问题:在一个数组里,只有一个元素出现了一次,其他元素都出现了两次,求这个元素的值

上面的思路是摘抄的,写下我自己的理解:A ^ B ^ C ^ C ^ D ^ D = A ^ B,因为是异或运算,假设A和B是相同的,结果一定是0,这样我们来寻找在二进制的最后某一位上为1的情况,a =10(1001),b = 7(0111) mask = a ^ b = (1101) mask = mask ^ (-mask) = 1;a =10(1001),b = 6(0110) mask = a ^ b = (1100) mask = mask ^ (-mask) = 4(100);所以我们的列表里面的值和mask与,结果(上面最后为1的那一位的结果)要么是零,要么是1,后面全是0,最终会分成两拨,a在一组里面,b在另一组里面,转化成在一个数组里,只有一个元素出现了一次,其他元素都出现了两次,求这个元素的值的问题。