n+1
的等差序列:S
,完整序列应为:S, S+1, S+2, ..., S+n
。n
的严格递增数组 nums
。n
个数仍然是连续的(公差仍为 1),此时数组内部无“断点”;否则会在被移除位置形成一个首次不连续点(从那一位开始都比“应有值”大 1)。expect(i) = nums[0] + i
k
个应有元素(值为 S+k
),则:i < k
:nums[i] == expect(i)
(完全吻合)i = k
起:nums[i] == expect(i) + 1
(开始偏大 1)nums[i] == nums[0] + i
” 在下标上是先真后假的单调布尔序列,能用二分找到第一个为假的位置。找到这个“第一个不满足”的下标 left
后:
nums[0] + left
。① nums[0]
S
,但在未断点之前,nums[i]
应等于 nums[0] + i
)。nums[mid] == mid + nums[0]
就是在判断“到 mid
这一段是否仍连续无缺口”。② left = mid + 1;
nums[mid] == nums[0] + mid
,说明到 mid 位置为止一切正常,缺口(如果存在)只能在右侧;③ right = mid;
nums[mid] != nums[0] + mid
,说明从 mid(含)开始已出现偏差,缺口的第一个位置不可能在右边,只能在左侧或就是 mid 本身;mid
保留该点继续查找“第一个不满足”。④ left + nums[0]
left
指向第一个不满足位置。该位置“应有值”是 nums[0] + left
,也就是被移除的真正数值(如果确有缺口)。left
推到 n-1
,此时返回的也是“该位置应有值”,用于做哨兵判断(见⑤)。⑤ nums[n-1]
nums[i] == nums[0] + i
,最终 left == n-1
,函数返回 nums[0] + (n-1)
;nums[n-1]
。missing_number == nums[n-1]
作为**“数组仍连续”的判据**,打印 "Sequence is consecutive"
;否则打印真正的缺失值。代码分析:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | #include <iostream> #include <vector> using namespace std; int find_missing(vector<int>& nums) { int left = 0, right = nums.size() - 1; while (left < right){ int mid = left + (right - left) / 2; if (nums[mid] == mid + nums[0]) { // ① 前半段连续 left = mid + 1; // ② 去右边找 } else { // 发生偏差的第一个位置在左侧(含mid) right = mid; // ③ 去左边收缩 } } // 此时left是“第一个不满足 nums[i] = nums[0] + i”的位置(若不存在,则left=n-1) return left + nums[0]; // ④ 缺失的就是应在left处的值 } int main() { int n; cin >> n; vector<int> nums(n); for (int i = 0; i < n; i++) cin >> nums[i]; int missing_number = find_missing(nums); if (missing_number == nums[n-1]) { // ⑤ 没有内部缺口(缺首或缺尾),数组仍连续 cout << "Sequence is consecutive" << endl; } else { cout << "Missing number is " << missing_number << endl; } return 0; } |