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)