LeetCode 260-只出现一次的数字 III

61 阅读2分钟

题目

给你一个整数数组 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 中的其他数字都出现两次

思路: 异或和+最低位1区分

仅有2个数字出现过一次,其他出现过2次,出现2次的数字可以用异或消除,但是后面会得到这两个数字的异或和,然后再区分出这俩数字。

如何区分出这两个数字?

首先,因为这两个数字,假设设为a,b,a!=b不相等,所以异或后得到的值,肯定不是0,不为0就说明至少有一位二进制为1。由于异或得到的值是相同的值为0,不同的位1。说明,这个二进制位的1,a,b的二进制中该位一定一个为0,另一个为1。

我们选择最低位1保留,其余位均为0的值来进行与运算,这样可以使用与运算,很好区分出该位是否为0 or 1,然后将a对应为0的异或,让b对应不为0的异或,这样就区分出来了a,b。

低位1保留计算方法

仅最低位1保留,计算方法:n&(~n+1) ~n

0 1 0 0 0 1 1 ... 1 0

~n + 1,结果就是n的最低位的1变成1

~ 1 1 1 1 0 0 ... 0 1

n&(~n+1)

0 0 0 0 0 0 ... 1 0

结论:任意 n&(~n+1) 得到的是n的最低位的1。

代码

class Solution:
    def singleNumber(self, nums: List[int]) -> List[int]:
        a, b = 0, 0
        xorsum = 0
        for i in nums:
            xorsum ^= i
        
        lsb = xorsum & (~xorsum + 1)
        for i in nums:
            if i & lsb == 0:
                a ^= i
            else:
                b ^= i
        return [a, b]