Leetcode之丢失的数字(268)、只出现一次的数字III(260)

1、丢失的数字(268)

题目描述:

【简单】

给定一个包含 [0, n] 中 n 个数的数组 nums ,找出 [0, n] 这个范围内没有出现在数组中的那个数。

进阶:

你能否实现线性时间复杂度、仅使用额外常数空间的算法解决此问题?

示例 1:

输入:nums = [3,0,1]
输出:2
解释:n = 3,因为有 3 个数字,所以所有的数字都在范围 [0,3] 内。2 是丢失的数字,因为它没有出现在 nums 中。

示例 2:

输入:nums = [0,1]
输出:2
解释:n = 2,因为有 2 个数字,所以所有的数字都在范围 [0,2] 内。2 是丢失的数字,因为它没有出现在 nums 中。

题目链接

思路分析:

1、与之前解过的 只出现一次的数字 有异曲同工之处,这里也可以使用「异或运算」巧妙的解决问题。
2、异或运算的结合律:a ^ b ^ c = a ^ (b ^ c) = (a ^ b) ^ c;

  • 自反:a ^ b ^ a = b.

3、需求:数组的长度为n,找到数组中在[0,n]缺失的范围
4、如果我们将数组与[0,n]即数组的下标+数组的长度进行异或,那么最后的结果就是缺失的数字

解答:

def missingNumber(self, nums):
        missing = len(nums)
        for i, num in enumerate(nums):
            missing ^= i ^ num
        return missing
  • 时间复杂度: O ( n ) O(n) O(n)
  • 空间复杂度: O ( 1 ) O(1) O(1)

2、只出现一次的数字III(260)

题目描述:

【中等】
给定一个整数数组 nums,其中恰好有两个元素只出现一次,其余所有元素均出现两次。 找出只出现一次的那两个元素。

题目链接

思路分析:

1、由于数组只有两个元素只出现一次,那么所有数异或得到的结果bitmask就是两个数的差异,如果要找的那两个数为x和y, 此时bitmask = x ^ y。在这里插入图片描述

  • 我们可以直接从 bitmask 中提取 x 和 y 吗?不能,但是我们可以用 bitmask 作为标记来分离 x 和 y。

2、由题知a != b,所有bitmask!= 0,所以最右侧一定有1。

  • 通过 bitmask & (-bitmask) 保留 bitmask 最右边的 1,这个 1 要么来自 x,要么来自 y。
    在这里插入图片描述

  • x & (-x) (x与其负数(反码+1)按位与结果是保留位中最右边 1 ,且将其余的 1 设位 0 的方法。

  • 在这里插入图片描述

3、找出最右侧那个1设为diff, 比如找到的1在第4位 diff = 00001000
4、则x的第4位和y的第4位一定是不同的,一个为0,一个为1,但是你不知道谁是0谁是1
5、将数组的每一个数 nums[i] & diff得到res,此时可分为两组。比如11001000 & 00001000 = 00001000, 另一组11000000 & 00001000 = 00000000 = 0;
6、第4位是1的与上diff 结果不等于0,第4位是0的与上diff等于0;
7、此时整个数组分成两组,第4位是1的一组,第4位是0的一组,此时x和y分别在两组里
8、一个结果为res ,则另一个结果为res ^bitmask ,比如res = x, x ^ bitmask=x ^x ^y = y;

解答:

class Solution:
    def singleNumber(self, nums: List[int]) -> List[int]:
        bitmask=0
        for num in nums:
            bitmask^=num
        diff =bitmask&(-bitmask)
        x=0
        for num in nums:
            if num & diff:
                x ^= num
        return [x,bitmask^x]
  • 时间复杂度: O ( n ) O(n) O(n)

  • 空间复杂度: O ( 1 ) O(1) O(1)

猜你喜欢

转载自blog.csdn.net/weixin_45666566/article/details/113042891