📜  在排序数组中找到唯一的遗漏号码(1)

📅  最后修改于: 2023-12-03 15:37:42.590000             🧑  作者: Mango

在排序数组中找到唯一的遗漏号码

概述

假设有一个已排序的数组,其中唯一的一个遗漏的数字在连续的数组中,例如 [1,2,3,4,6,7,8]。或者遗漏数字在数组的开头或结尾。找出这个唯一的遗漏数字。

解法
1. 暴力枚举

最简单的方法是暴力地枚举整个数组,找到遗漏的数字。由于数组已排序,如果当前数字 nums[i] 不等于 i+1,那么遗漏的数字就是 i+1

复杂度是 $O(n)$,即使没有遗漏数字,也会遍历整个数组。

2. 二分查找

由于数组已排序,又只有一个遗漏数字,我们可以使用二分查找来找到它。例如,对于 [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)$。

3. 位运算

对于这种问题,我们可以使用异或运算。因为异或运算满足交换律和结合律,因此异或相同的数字会得到 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)$。

代码
1. 暴力枚举
def find_missing_number(nums):
    for i, num in enumerate(nums):
        if num != i+1:
            return i+1
2. 二分查找
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
3. 位运算
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