
本文介绍一种针对已排序、含重复元素、范围达千万级的整数数组,快速定位唯一缺失数字的线性扫描算法——无需额外空间、不依赖哈希或二分,兼顾简洁性、鲁棒性与工业级性能。
本文介绍一种针对**已排序、含重复元素、范围达千万级**的整数数组,快速定位唯一缺失数字的线性扫描算法——无需额外空间、不依赖哈希或二分,兼顾简洁性、鲁棒性与工业级性能。
在实际数据处理场景中(如日志序列号校验、传感器采样补全、分布式ID段验证),我们常遇到这样一类数组:元素严格升序排列,数值范围连续但存在恰好一个缺失值,同时允许任意数量的重复项。此时,经典“等差求和法”或“异或抵消法”因重复干扰而失效;而试图沿用二分搜索的思路也会失败——因为重复与缺失共存时,左右子区间的元素个数与理论值偏差无法唯一映射到缺失位置(例如:[1,2,2,4] 与 [1,2,3,4] 的左半段均为 [1,2],但前者缺3、后者无缺)。
因此,最优解需回归问题本质特征:数组已排序。只要遍历相邻元素对,检查差值即可直接捕获缺失点:
- 若 ar[i] - ar[i-1] == 1:正常递进;
- 若 ar[i] - ar[i-1] == 0:纯重复,跳过;
- 若 ar[i] - ar[i-1] == 2:说明 ar[i-1] + 1 缺失(即 ar[i] - 1);
- 若差值 > 2(如 3 或更大):则存在多个缺失,与题设“唯一缺失”矛盾,可视为输入异常。
该逻辑时间复杂度为 O(n),空间复杂度 O(1),且对千万级数组实测性能极佳(平均约 5ms)。以下是 Java 实现示例:
public static int findMissing(int[] arr) {
if (arr == null || arr.length < 2) return -1;
for (int i = 1; i < arr.length; i++) {
int diff = arr[i] - arr[i - 1];
if (diff == 2) {
return arr[i] - 1; // 唯一缺失值
}
if (diff > 2) {
throw new IllegalArgumentException("Multiple missing numbers detected: " +
"gap " + diff + " at index " + i);
}
// diff == 0 or diff == 1: skip duplicates or normal increment
}
return -1; // no missing found
}关键注意事项:
✅ 前提强约束:数组必须严格升序(非非降序),且仅含整数;
✅ 题设隐含“有且仅有一个缺失”,算法未做缺失数不存在的兜底,可根据业务需要返回 -1 或抛出异常;
✅ 重复不影响正确性——算法天然忽略 diff == 0 的情况,仅关注 diff == 2 这一决定性信号;
✅ 不适用于无序数组;若输入无序,请先排序(O(n log n))或改用哈希集合(O(n) 时间+O(n) 空间);
✅ 对于超大规模(如十亿级),可考虑分块并行扫描(需保证块边界不割裂相邻关系),但单线程已足够应对绝大多数生产场景。
总结而言,在“有序+唯一缺失+允许重复”这一特定约束下,一次线性遍历是最简、最稳、最快的选择——它不炫技,却直击要害。










