以下是我的解决方案,我认为它很简单,并且避免了过多令人困惑的 if 语句。当您不从 0 开始或涉及负数时,它也有效!假设客户端拥有数字数组(否则为 O(n) )。
C 代码中的算法
int missingNumber(int a[], int size) {
int lo = 0;
int hi = size - 1;
// TODO: Use this if we need to ensure we start at 0!
//if(a[0] != 0) { return 0; }
// All elements present? If so, return next largest number.
if((hi-lo) == (a[hi]-a[lo])) { return a[hi]+1; }
// While 2 or more elements to left to consider...
while((hi-lo) >= 2) {
int mid = (lo + hi) / 2;
if((mid-lo) != (a[mid]-a[lo])) { // Explore left-hand side
hi = mid;
} else { // Explore right hand side
lo = mid + 1;
}
}
// Return missing value from the two candidates remaining...
return (lo == (a[lo]-a[0])) ? hi + a[0] : lo + a[0];
}
测试输出
int a[] = {0}; // Returns: 1
int a[] = {1}; // Returns: 2
int a[] = {0, 1}; // Returns: 2
int a[] = {1, 2}; // Returns: 3
int a[] = {0, 2}; // Returns: 1
int a[] = {0, 2, 3, 4}; // Returns: 1
int a[] = {0, 1, 2, 4}; // Returns: 3
int a[] = {0, 1, 2, 4, 5, 6, 7, 8, 9}; // Returns: 3
int a[] = {2, 3, 5, 6, 7, 8, 9}; // Returns: 4
int a[] = {2, 3, 4, 5, 6, 8, 9}; // Returns: 7
int a[] = {-3, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // Returns: -1
int a[] = {-3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; // Returns: 10
一般流程是:
- (可选)检查数组是否从 0 开始。如果不是,则返回 0 作为缺失。
- 检查整数数组是否完整且没有缺失整数。如果不缺少整数,则返回下一个最大的整数。
- 以二分查找方式,检查索引和数组值之间的差异是否不匹配。不匹配告诉我们缺少的元素在哪一半。如果前半部分不匹配,则向左移动,否则向右移动。这样做,直到您有两个候选元素需要考虑。
- 根据不正确的候选人返回缺少的数字。
注意,算法的假设是:
- 第一个和最后一个元素被认为永远不会丢失。这些元素建立了一个范围。
- 数组中只缺少一个整数。这将找不到一个以上的缺失整数!
- 预计数组中的整数会以 1 为步长增加,而不是以任何其他速率增加。