试卷解析 · 理解每一步
2026-09-Level-5
2026-09-Level-5
试卷解析总览,可直接查看每题答案与解析。
第 1 题(单选题,2 分)
小杨用单链表保存任务序列,并同时维护头指针 head 和尾指针 tail 。在链表非空且已知 tail 的情况下,在表尾插入新结点的时间复杂度是( )。
struct Node {
int value;
Node *next;
};
Node *head;
Node *tail;正确答案A
解析详情
已知尾指针tail后,只需把tail->next指向新结点并更新tail,不需要遍历链表,因此时间复杂度为O(1),选A。
第 2 题(单选题,2 分)
在不带哨兵结点的双向链表中,结点 p 既不是头结点也不是尾结点。删除 p 的正确代码是( )。
struct Node {
int value;
Node *prev;
Node *next;
};p->prev = p->next;
p->next = p->prev;
delete p;p->prev->next = p;
p->next->prev = p;
delete p;p->prev->next = p->next;
p->next->prev = p->prev;
delete p;p->next = p->prev;
p->prev->next = nullptr;
delete p;正确答案C
解析详情
删除中间结点前,应让前驱的next指向后继、后继的prev指向前驱,再释放p。C同时修复两个方向的链接,选C。
第 3 题(单选题,2 分)
下面函数使用快慢指针查找单链表的中间结点。横线处应填写( )。
struct Node {
int value;
Node *next;
};
Node *middle(Node *head) {
Node *slow = head;
Node *fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
______________________
}
return slow;
}fast = fast->next;fast = fast->next->next;fast = slow->next;fast = head->next;正确答案B
解析详情
slow每轮走一步,fast应走两步。fast到达链尾时slow位于中间,因此填写fast=fast->next->next,选B。偶数长度时此写法返回靠后的中间结点。
第 4 题(单选题,2 分)
函数 gcd(int a, int b) 定义如下,则 gcd(105, 45) 的结果是( )。
int gcd(int a, int b) {
return b == 0 ? a : gcd(b, a % b);
}正确答案C
解析详情
105除以45余15,随后45除以15余0,因此gcd(105,45)=gcd(45,15)=15,选C。
第 5 题(单选题,2 分)
下面函数用于判断正整数 n 是否为质数。横线处的最佳写法是( )。
bool isPrime(int n) {
if (n < 2)
return false;
for (int i = 2; __________________; i++) {
if (n % i == 0)
return false;
}
return true;
}i < ni <= n / 2i * i < n(long long) i * i <= n正确答案D
解析详情
合数必有不超过平方根的因子,必须包含i*i==n,才能识别完全平方数。D还先转换为long long避免int乘法溢出,因此是最佳写法。
第 6 题(单选题,2 分)
下面代码实现线性筛法。为了保证每个合数只被其最小质因子筛去一次,横线处应填写( )。
vector<int> linearSieve(int n) {
vector<bool> composite(n + 1, false);
vector<int> primes;
for (int i = 2; i <= n; i++) {
if (!composite[i])
primes.push_back(i);
for (int p : primes) {
if ((long long)i * p > n)
break;
composite[i * p] = true;
if (__________________)
break;
}
}
return primes;
}p % i == 0i % p == 0i == pi * p == n正确答案B
解析详情
当i%p==0时,p已是i的最小质因子,应立即停止,避免后续更大的质数把相同合数重复筛去。因此填写i%p==0,选B。
第 7 题(单选题,2 分)
根据唯一分解定理,整数 的正确质因数分解是( )。
正确答案A
解析详情
756=4×189=2²×3³×7,所有底数均为质数,选A。C、D虽也能乘出756,却仍含21、14这样的合数,不是完整质因数分解。
第 8 题(单选题,2 分)
函数 f(int n) 定义如下,则 f(4) 的结果是( )。
int f(int n) {
if (n == 1)
return 1;
return n + f(n - 1);
}正确答案D
解析详情
f(4)=4+f(3)=4+3+f(2)=4+3+2+1=10,选D。n=1的返回值是递归终止条件。
第 9 题(单选题,2 分)
在升序数组中查找第一个严格大于 x 的元素位置,下面代码中的横线应填写( )。
int upperBound(const vector<int> &a, int x) {
int l = 0, r = (int)a.size();
while (l < r) {
int mid = l + (r - l) / 2;
if (__________________) {
l = mid + 1;
} else {
r = mid;
}
}
return l;
}a[mid] < xa[mid] >= xa[mid] <= xa[mid] > x正确答案C
解析详情
目标是第一个严格大于x的位置。当a[mid]<=x时,mid以及更左侧都不满足要求,应把l移动到mid+1,因此选C。
第 10 题(单选题,2 分)
小杨需要把若干箱货物按原顺序分配到 days 天中,每天运输连续的若干箱,求能够完成任务的最小载重量。函数 check(cap) 判断载重量为 cap 时能否在规定天数内运完。横线处应填写( )。
long long l = maxWeight;
long long r = totalWeight;
while (l < r) {
long long mid = l + (r - l) / 2;
if (check(mid)) {
____________________
} else {
____________________
}
}
cout << l;l = mid + 1;和r = mid;r = mid;和l = mid + 1;r = mid - 1;和l = mid;l = mid;和r = mid - 1;正确答案B
解析详情
载重可行时mid仍可能是最小答案,应保留mid并缩小上界r=mid;不可行时mid及更小值都不行,令l=mid+1,因此选B。
第 11 题(单选题,2 分)
下面是归并排序中合并两个有序区间(升序排序)的部分代码。若希望排序保持稳定,横线处应填写( )。
while (i <= mid && j <= right) {
if (__________________) {
temp.push_back(a[i++]);
} else {
temp.push_back(a[j++]);
}
}a[i] < a[j]a[i] > a[j]a[i] >= a[j]a[i] <= a[j]正确答案D
解析详情
左区间的相等元素在原序列中更靠前,所以相等时应优先取左边a[i]。使用a[i]<=a[j]同时保证升序与稳定性,选D。
第 12 题(单选题,2 分)
下面快速排序的划分函数以 a[right] 为枢轴,并把不大于枢轴的元素移动到左侧。横线处应填写( )。
int partition(int a[], int left, int right) {
int pivot = a[right];
int i = left - 1;
for (int j = left; j < right; j++) {
if (__________________) {
i++;
swap(a[i], a[j]);
}
}
swap(a[i + 1], a[right]);
return i + 1;
}a[j] <= pivota[j] > pivota[i] <= pivota[right] < a[j]正确答案A
解析详情
j扫描当前元素,若a[j]<=pivot,就把它交换进左侧区间并扩大该区间,因此选A。最终再把枢轴放到i+1。
第 13 题(单选题,2 分)
小杨要在一个教室安排尽可能多场活动,每场活动具有开始时间 start 和结束时间 end 。采用贪心算法时,正确的选择策略是( )。
struct Activity {
int start;
int end;
};正确答案D
解析详情
选择结束最早的兼容活动,给后续活动留下最多时间。把最优方案的首场替换成结束更早的活动不会减少后续选择,因此D的策略正确。
第 14 题(单选题,2 分)
下面函数使用迭代方法求最大连续子段和。对于数组 {-2, 3, -1, 5, -6, 2} ,函数返回值是( )。
int maxSubArray(const vector<int> &a) {
int best = a[0];
int current = a[0];
for (int i = 1; i < (int)a.size(); i++) {
current = max(a[i], current + a[i]);
best = max(best, current);
}
return best;
}正确答案C
解析详情
current依次为−2、3、2、7、1、3,best的最大值为7,对应连续子段3、−1、5,选C。
第 15 题(单选题,2 分)
数组 a 和 b 按低位在前的顺序保存两个非负大整数。下面代码实现高精度加法,横线处应填写( )。
vector<int> add(const vector<int> &a, const vector<int> &b) {
vector<int> c;
int carry = 0;
int n = max(a.size(), b.size());
for (int i = 0; i < n; i++) {
int sum = carry;
if (i < a.size())
sum += a[i];
if (i < b.size())
sum += b[i];
c.push_back(sum % 10);
____________________
}
if (carry)
c.push_back(carry);
return c;
}carry = sum % 10;carry = sum;carry = sum / 10;carry = c[i] / 10;正确答案C
解析详情
sum%10保存当前位,sum/10才是传给下一位的进位,因此填写carry=sum/10,选C。例如9+8+1=18,当前位为8,进位为1。
判断题
第 1 题(判断题,2 分)
下面代码在已知结点 p 的情况下,能够以 的时间在单链表的 p 结点之后插入新结点 s 。
s->next = p->next;
p->next = s;正确答案正确
解析详情
已知p后,两次指针赋值就能把s接入p之后,不需要寻找位置,时间为O(1),因此正确。
第 2 题(判断题,2 分)
下面代码可以安全地删除单链表的头结点,并使 head 指向删除后的新头结点。
Node *p = head;
delete p;
head = p->next;正确答案错误
解析详情
delete p之后对象已经被释放,再访问p->next属于释放后访问,不能安全得到新头结点,因此错误。应先保存后继或更新head,再释放旧结点。
第 3 题(判断题,2 分)
下面欧几里得算法既适用于 a > b ,也适用于 a < b ,只要 a 、 b 是正整数。
int gcd(int a, int b) {
while (b != 0) {
int r = a % b;
a = b;
b = r;
}
return a;
}正确答案正确
解析详情
若a<b,第一次a%b=a,更新后相当于交换为(b,a),随后正常执行辗转相除。因此对任意正整数a、b均适用,表述正确。
第 4 题(判断题,2 分)
下面埃氏筛从 i * i 开始标记,是因为 i * i 之前的 i 的合数倍数已经被更小的质因子标记过。
for (int i = 2; (long long)i * i <= n; i++) {
if (isPrime[i]) {
for (int j = i * i; j <= n; j += i) {
isPrime[j] = false;
}
}
}正确答案正确
解析详情
小于i*i的合数倍数可写成i*k且k<i,k具有更小的质因子,之前已被筛去,所以从i*i开始不会遗漏,表述正确。
第 5 题(判断题,2 分)
下面程序的时间复杂度为 。
for (int i = 1; i <= n; i *= 2) {
cout << i << endl;
}正确答案错误
解析详情
i依次为1、2、4、8等,约执行log₂n+1轮,紧确增长阶为O(log n),不是题目意图中的线性复杂度,因此错误。
第 6 题(判断题,2 分)
若数组 a 已按升序排列,下面函数能够返回最后一个小于等于 x 的元素下标;如果不存在,则返回-1 。
int findLastLE(const vector<int> &a, int x) {
int l = 0, r = (int)a.size() - 1;
int ans = -1;
while (l <= r) {
int mid = l + (r - l) / 2;
if (a[mid] <= x) {
ans = mid;
l = mid + 1;
} else {
r = mid - 1;
}
}
return ans;
}正确答案正确
解析详情
a[mid]<=x时记录mid,再向右查找更靠后的可行位置;否则缩小右边界。若始终无可行元素,ans保持−1,因此正确。
第 7 题(判断题,2 分)
快速排序中如果选取区间第一个元素作为枢轴。当输入数组已经升序排列时,其最坏时间复杂度仍为 。
正确答案错误
解析详情
有序数组总选第一个元素为枢轴,会分出0个和n−1个元素,递归极不平衡,总比较次数为平方级,不能保持O(n log n),因此错误。
第 8 题(判断题,2 分)
归并排序的递推式为 ,对应的时间复杂度为 。
正确答案正确
解析详情
每层把问题分成两个规模约n/2的子问题,合并总工作量为O(n)。递归约有log₂n层,因此总复杂度为O(n log n),表述正确。
第 9 题(判断题,2 分)
下面的贪心代码一定能对任意硬币面值集合 coins 求出 money 所需的最少硬币数。
int count = 0;
for (int coin : coins) { // coins 按面值从大到小排列
count += money / coin;
money %= coin;
}正确答案错误
解析详情
例如面值为4、3、1,金额为6,贪心取4+1+1共3枚,但3+3只要2枚。因此该方法不适用于任意面值集合,表述错误。
第 10 题(判断题,2 分)
假设两个非负高精度整数分别存储在数组 a 和 b 中,且 。数组采用低位在前的方式存储,即a[0] 表示个位。下面代码中的 c 可以正确保存 a - b 的各位数字。
int borrow = 0;
for (int i = 0; i < len; ++i) {
int t = a[i] - b[i] + borrow;
if (t < 0) {
t += 10;
borrow = 1;
} else {
borrow = 0;
}
c[i] = t;
}正确答案错误
解析详情
上一位借走1后,本位应减去borrow,代码却加上borrow。例如20−1会算出低位9、高位3,即39而不是19,因此错误。