📅  最后修改于: 2023-12-03 15:37:42.590000             🧑  作者: Mango
假设有一个已排序的数组,其中唯一的一个遗漏的数字在连续的数组中,例如 [1,2,3,4,6,7,8]
。或者遗漏数字在数组的开头或结尾。找出这个唯一的遗漏数字。
最简单的方法是暴力地枚举整个数组,找到遗漏的数字。由于数组已排序,如果当前数字 nums[i]
不等于 i+1
,那么遗漏的数字就是 i+1
。
复杂度是 $O(n)$,即使没有遗漏数字,也会遍历整个数组。
由于数组已排序,又只有一个遗漏数字,我们可以使用二分查找来找到它。例如,对于 [1,2,3,4,6,7,8]
,我们可以将数组分成两个部分:[1,2,3,4]
和 [6,7,8]
。看到前一半的末尾数是 4,但实际上这一半应该有 5 个数,因此遗漏的数字一定在这一半。
在这一半中,我们将其又分成两个部分:[1,2]
和 [3,4]
。看到前一半的末尾数是 2,但实际上这一半应该有 3 个数,因此遗漏的数字一定在这一半。
以此类推,我们可以不断地二分查找,直到找到遗漏的数字。
复杂度是 $O(\log n)$。
对于这种问题,我们可以使用异或运算。因为异或运算满足交换律和结合律,因此异或相同的数字会得到 0,异或不同的数字会得到它们的异或值。
对于 [1,2,3,4,6,7,8]
,我们先将数组中的所有数字依次异或,得到的结果是 1^2^3^4^6^7^8,即遗漏数字的异或值。如果没有遗漏数字,这个异或值应该是数组中所有数字的异或值,也就是 1^2^3^4^5^6^7^8。
如果两个相同的数字异或,结果为 0。因此我们可以将所有数字从 1 到 n 进行异或运算,得到的结果就是遗漏数字。可以证明,这个算法的复杂度是 $O(n)$。
def find_missing_number(nums):
for i, num in enumerate(nums):
if num != i+1:
return i+1
def find_missing_number(nums):
left, right = 0, len(nums)-1
while left <= right:
mid = (left + right) // 2
if nums[mid] != mid + 1 and nums[mid-1] == mid:
return mid + 1
elif nums[mid] != mid + 1:
right = mid - 1
else:
left = mid + 1
def find_missing_number(nums):
n = len(nums)
xor_sum = 0
for i in range(n):
xor_sum = xor_sum ^ nums[i] ^ (i+1)
return xor_sum