唯一分解定理描述的内容是( )?
B:唯一分解定理即算术基本定理,每个大于 1 的整数都能唯一写成素数乘积(不计顺序),合数自然包含在内。A 的任意整数含 0、1、负数不成立;C 若素数乘积相同则两数必相等,违反唯一性。
贪心算法的核心思想是( )?
A:贪心算法的标准定义是每一步都做当前状态下的最优选择,并希望累积出全局最优。B 的局部最优解表述只在满足贪心选择性质与最优子结构的问题上成立,不能概括其核心思想;C 每步选全局最优无法实现。
下面的 C++ 代码片段用于计算阶乘。请在横线处填入( ),实现正确的阶乘计算。
01int factorial(int n) { 02 if (n == 0 || n == 1) { 03 return 1; 04 } else { 05 ____________ // 在此处填入代码 06 } 07}
A:n! = n×(n-1)!,递归出口已处理 n 为 0 或 1 时返回 1,else 分支应返回 n*factorial(n-1)。B 用除法结果错,C 调用 factorial(n) 自身不缩小参数会无限递归,D 拆成两个 n/2 的阶乘相乘不是 n!。
下面的代码片段用于在双向链表中删除一个节点。请在横线处填入( ),使其能正确实现相应功能。
01void deleteNode(DoublyListNode*& head, int value) { 02 DoublyListNode* current = head; 03 while (current != nullptr && current->val != value) { 04 current = current->next; 05 } 06 if (current != nullptr) { 07 if (current->prev != nullptr) { 08 ____________ // 在此处填入代码 09 } else { 10 head = current->next; 11 } 12 if (current->next != nullptr) { 13 current->next->prev = current->prev; 14 } 15 delete current; 16 } 17}
B:current 非头结点时让前驱的 next 跳过:current->prev->next = current->next;后面代码处理 current->next->prev = current->prev 再 delete current。A 与已有行重复,C 误删后继,D 改错指针方向。
辗转相除法也被称为( )
C:辗转相除法由欧几里得在《几何原本》中系统给出,故又称欧几里得算法,用于求最大公约数。高斯消元法解线性方程组,费马定理是数论定理,牛顿迭代法求方程近似根。
下面的代码片段用于计算斐波那契数列。该代码的时间复杂度是( )?
01int fibonacci(int n) { 02 if (n <= 1) { 03 return n; 04 } else { 05 return fibonacci(n - 1) + fibonacci(n - 2); 06 } 07}
C:fibonacci(n) 每次递归调用自身两次,递推式 T(n)=T(n-1)+T(n-2)+O(1),递归树以约 2 的幂指数膨胀,复杂度为 O(2^n)(实际约为 φ^n),远高于 O(n) 和 O(log n)。
下面的代码片段用于将两个高精度整数进行相加。请在横线处填入( ),使其能正确实现相应功能。
01string add(string num1, string num2) { 02 string result; 03 int carry = 0; 04 int i = num1.size() - 1, j = num2.size() - 1; 05 while (i >= 0 || j >= 0 || carry) { 06 int x = (i >= 0) ? num1[i--] - '0' : 0; 07 int y = (j >= 0) ? num2[j--] - '0' : 0; 08 int sum = x + y + carry; 09 carry = sum / 10; 10 ____________ 11 } 12 return result; 13}
A:x、y 取到当前位数字后,sum=x+y+carry 已含进位,当前位应写 sum%10,进位 carry=sum/10 供下一轮使用;把 sum%10 拼到 result 前面(高位在左)。B、C 都取了进位或商而非个位,D 又把 carry 重复加进当前位。
给定序列:。使用以下代码进行二分查找查找元素 82 时,需要循环多少次,即最后输出的 times 值为( )。
01int binarySearch(const std::vector<int>& arr, int target) { 02 int left = 0; 03 int right = arr.size() - 1; 04 int times = 0; 05 while (left <= right) { 06 times ++; 07 int mid = left + (right - left) / 2; 08 if (arr[mid] == target) { 09 cout << times << endl; 10 return mid; 11 } else if (arr[mid] < target) { 12 left = mid + 1; 13 } else { 14 right = mid - 1; 15 } 16 } 17 cout << times << endl; 18 return -1; 19}
D:13 个数下标 0~12,查 82 时 mid 为 6(39<82,left 变 7)、9(79<82,left 变 10)、11(90>82,right 变 10)、10(81<82,left 变 11),left=11>right=10 退出,共 4 次循环,times=4、返回 -1。
下面的代码片段用于判断一个正整数是否为素数。请对以下代码进行修改,使其能正确实现相应功能。( )
01bool isPrime(int num) { 02 if (num < 2) { 03 return false; 04 } 05 for (int i = 2; i * i < num; ++i) { 06 if (num % i == 0) { 07 return false; 08 } 09 } 10 return true; 11}
B:原条件 ii<num 漏判完全平方数,如 num=4 时 i=2 不满足 4<4,循环不执行就误返回 true;改为 ii<=num 后 4 会被 4%2==0 判为合数。A 把素数 2 误判,C 中 i=num 时 num%num==0 必误判,D 逻辑颠倒。
在埃拉托斯特尼筛法中,要筛选出不大于 n 的所有素数,最外层循环应该遍历什么范围( )?
01vector<int> sieveOfEratosthenes(int n) { 02 std::vector<bool> isPrime(n + 1, true); 03 std::vector<int> primes; 04 ____________ { 05 if (isPrime[i]) { 06 primes.push_back(i); 07 for (int j = i * i; j <= n; j += i) { 08 isPrime[j] = false; 09 } 10 } 11 } 12 for (int i = sqrt(n) + 1; i <= n; ++i) { 13 if (isPrime[i]) { 14 primes.push_back(i); 15 } 16 } 17 return primes; 18}
C:外层只需让 i 从 2 到 sqrt(n):若 isPrime[i] 则把 i 记入 primes,并从 j=i*i 开始把 i 的倍数标为合数;sqrt(n) 之后的素数由第二段循环补记。A 会让第二段把素数重复加入,B、D 从 i=1 开始会把 1 误当素数。
素数的线性筛法时间复杂度为( )。
A:线性筛(欧拉筛)用最小质因子标记每个合数,保证每个合数只被筛一次,每个数至多处理常数次,总复杂度为 O(n),优于埃氏筛的 O(n log log n)。
归并排序的基本思想是( )。
B:归并排序把序列不断二分直至单元素,再自底向上两两合并有序子序列,是分治的分解-求解-合并三步骤的典型体现;动态规划、贪心、回溯都不是其基本思想。
在快速排序中,选择的主元素(pivot)会影响算法的( )。
B:pivot 的选择决定每趟划分是否均衡,直接影响时间复杂度——划分均衡时 O(n log n),每次选到最大或最小值则退化为 O(n²);空间复杂度主要由递归深度决定,与 pivot 关系不大。
递归函数在调用自身时,必须满足( ),以避免无限递归?
A:避免无限递归的充要条件是存在终止条件(base case),满足时直接返回、不再调用自身。B 的参数递减只是保证能到达终止条件的常用手段而非必须;C 返回值固定与递归终止无关。
假设给定链表为:,若调用 searchValue(head, 5),函数返回值为( )。
01int searchValue(ListNode* head, int target) { 02 while (head != nullptr) { 03 if (head->val == target) { 04 return 1; 05 } 06 head = head->next; 07 } 08 return 0; 09}
A:searchValue 从 head 沿 next 指针逐个比较节点值,链表 1→3→5→7 中第三个节点的 val 为 5,命中后立即 return 1,不会走到链表末尾,故返回 1 而非 0。
辗转相除法用于求两个整数的最大公约数。
对。辗转相除法(欧几里得算法)基于 gcd(a,b)=gcd(b,a%b),反复用较大数对较小数取余,余数为 0 时除数即两数最大公约数,正是求 gcd 的标准算法。
插入排序的时间复杂度是 。
错。插入排序每轮把当前元素向前插入已有序区,最坏与平均都是 O(N²)(如逆序时每轮都要移动到最前),最好情况才 O(N),不是 O(N log N)。
二分查找要求被搜索的序列是有序的,否则无法保证正确性。
对。二分查找靠比较中间元素与目标来决定去左半还是右半,前提是序列单调有序;若无序,中间元素的大小无法指示目标所在半边,可能漏掉目标,无法保证正确。
使用贪心算法解决问题时,每一步的局部最优解一定会导致全局最优解。
错。每一步局部最优并不保证最终全局最优,还需满足贪心选择性质与最优子结构;例如 0/1 背包按单位价值贪心选择就得不到最优解,所以该说法不成立。
分治算法的核心思想是将一个大问题分解成多个相同或相似的子问题进行解决,最后合并得到原问题的解。
对。分治三步正是把大问题分解成相同或相似的子问题、分别解决、再把子解合并成原问题的解,如归并排序先拆两半分别排序再合并,完全符合题目描述。
分治算法的典型应用之一是归并排序,其时间复杂度为 。
对。归并排序把序列递归二分到单元素,再逐层两两合并有序段,每层合并共 O(N),共 log N 层,总时间 O(N log N),是分治法分解-求解-合并的典型应用。
素数表的埃氏筛法和线性筛法的时间复杂度都是 。
错。埃氏筛的时间复杂度是 O(N log log N),而线性筛(欧拉筛)保证每个合数只被其最小质因子筛一次,总复杂度为 O(N),两者并不相同。
贪心算法是一种可以应用于所有问题的通用解决方案。
错。贪心只适用于具备贪心选择性质和最优子结构的问题,许多问题如一般的 0/1 背包、旅行商问题贪心无法得到全局最优,它不是能解决所有问题的通用方案。
单链表和双链表都可以在常数时间内实现在链表头部插入或删除节点的操作。
对。头插只需新建节点使其 next 指向原 head 再更新 head(双链表再补 prev),头删直接 head=head->next 并处理 prev,均无需沿链表查找,所以是常数时间 O(1)。
在 C 语言中,递归的实现方式通常会占用更多的栈空间,可能导致栈溢出。
对。每次递归调用都会在栈上压入新的函数栈帧,保存参数、局部变量与返回地址,递归层数深时栈空间被耗尽即发生栈溢出,无终止条件的递归更会直接溢出。