三、完善程序(单选题,每小题 3 分,共计 30 分)
一、题目阅读
(寻找被移除的元素)问题: 原有长度为 n+1 公差为 1 等差数列,将数列输到程序的数组时移除了一个元素,导致长度为 n 的连续数组可能不再连续,除非被移除的是第一个或最后一个元素。需要在数组不连续时,找出被移除的元素。试补全程序。
#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 + ①) { ②; } else { ③; } } return ④; } 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 == ⑤) { cout << "Sequence is consecutive" << endl; }else{ cout << "Missing number is " << missing_number << endl; } return 0; }
二、程序分析
既然题目已经告诉我们要做的了,那我们不妨用二分模拟一下找出被移除元素的过程。
nums = {3, 4, 5, 7, 8}
我们第一次找到num[2] = 5,这时怎么判断在要找的位置的左边还是右边呢?我们知道,这个序列的第一个元素不固定,所以不能直接拿下标去判断。不过我们可以获取第一个元素,3,按理来说等差数列的第n个的值就是首项 + 公差 * (n - 1),所以此处可以算出来本应是
3 + 2 * 1 = 5,而5 == 5,所以往后面找。
第二次,找到7,3 + 3 * 1 = 6,所以锁定在这个位置了。现在结合文中部分代码,
right应该 = 7的位置,不可以小于7,这样就定了第三题的答案。
然后循环条件不满足,跳了出来。
然后可以根据当前下标与第一个数推算出结果。
三、题目分析
1. ①处应填(B)
A. 1
B. nums[0]
C. right
D. left【计算等差数列中一个位置的数值,必然跟第一个数的值有关】】
2. ②处应填(A)
A. left=mid+1
B. right=mid-1
C. right=mid
D. left=mid【当该数值正确时,结合第4题理解,到最后(left==right)left指向缺少的值的后面一个下标,说明这不可能是缺少的后一个,应把空间往右缩进,同时+1】
3. ③处应填(C)
A. left=mid+1
B. right=mid-1
C. right=mid
D. left=mid【发现数值不符合等差数列的要求,要把空间往左缩进,但不能减一,应为不排除它是缺少的数的下一个下标的可能】
4. ④处应填(A或者B)
A. left+nums[0]
B. right+nums[0]
C. mid+nums[0]
D. right+1【本题有问题,出循环时left == right,所以AB都行,但是比赛时遇到应选A,因为A为常规做法】
5. ⑤处应填(D)A. nums[0]+n
B. nums[0]+n-1
C. nums[0]+n+1
D. nums[n-1]【当该数组为等差数列时,left不断往右移动,最终与right(n - 1)重合而止,所以应该与最后一个数字做比较】