2023 csp-j第一轮解析

本文解析了CSP-J第一轮竞赛中的多项选择题和程序题,涵盖C++关键字、八进制加法、联合体变量赋值等内容,并提供了详细的解答。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

单选选择

  1. 在 C++ 中,下面哪个关键字用于声明一个变量, 其值不能被修改?
    A unsigned
    B const
    C static
    D mutable
    答案: B. const
    解析:在C++中, const 关键字用于声明常量,这意味着一旦给该变量赋值,就不能再修改它。其他选项不具有这种属性。

  2. 八进制数123456708和076543218 的和为
    A (22222221)8
    B (21111111)8
    C (22111111)8
    D (22222211)8
    答案: D. (22222211)8
    为了求解两个八进制数的和,我们可以按照常规的加法方法进行,从最低位开始加,记住进位。
    首先,我们列出两个八进制数:

``12345670
+ 07654321
------------------

从最右边开始加:
0 + 1 = 1
7 + 2 = 9。但在八进制中, 9是无效的。所以,我们写下1,并进位1。
6 + 3 = 9。再加上前面进位的1,得到10。所以,我们写下2,并进位1。
5 + 4 = 9。再加上前面进位的1,得到10。所以,我们写下2,并进位1。
4 + 5 = 9。再加上前面进位的1,得到10。所以,我们写下2,并进位1。
3 + 6 = 9。再加上前面进位的1,得到10。所以,我们写下2,并进位1。
2 + 7 = 9。再加上前面进位的1,得到10。所以,我们写下2,并进位1。
1 + 0 = 1。再加上前面进位的1,得到2。
将结果写下来:
``12345670
+ 07654321
------------------
22222211

所以,答案是: (22222211)8
选项D是正确的。

  1. 阅读下述代码,请问修改data 的 value 成员以存储3.14,正确的方式是
    union Data{
    int num;
    float value;
    char symbol;
    };
    union Data data;
    A data.value =3.14;
    B value.data=3.14;
    C data->value = 3.14;
    D value->data = 3.14;
    答案: A. data.value =3.14;
    解析:根据给定的联合UNION定义,我们可以直接通过联合名访问其成员。因此,正确的方式是使用data.value。其它选项都是语法上不 正确的。

  2. 假设有一个链表的节点定义如下:
    struct Node {
    int data;
    Node* next;
    }
    现在有一个指向链表头部的指针: Node* head。如果想要在链表中插入一个新节点,其成员data的值为42,并使新节点成为链表的第一个 节点,下面哪个操作是正确的?
    A Node* newNode = new Node; newNode->data = 42; newNode->next = head; head = newNode;
    B Node* newNode = new Node; head->data = 42; newNode->next = head; head = newNode;
    C Node* newNode = new Node; newNode->data = 42; head->next = newNode;
    D Node* newNode = new Node; newNode->data = 42; newNode->next = head;
    答案: A;
    解析:首先,我们需要创建一个新的节点。然后,我们为新节点的数据成员赋值42。接下来,我们将新节点的next成员设置为当前的头节 点,最后更新头指针以指向新节点。这样,新节点就成为了链表的第一个节点。

  3. 根节点的高度为1 ,一棵拥有2023个节点的三叉树高度至少为()。
    A 6
    B 7
    C 8
    D 9
    答案: C
    解析:对于高度为 h 的完全三叉树,其节点数最少为 3^0 + 3^1 + … + 3^(h-1)。
    比如对于高度为6的完全三叉树,其节点数为364。对于高度为7的完全三叉树,其节点数为1093。
    考虑到我们有2023个节点,这意味着树的高度至少为8,因为高度为7的三叉树无法容纳这么多节点。

  4. 小明在某一天中依次有七个空闲时间段,他想要选出至少一个空闲时间段来练习唱歌,但他希望任意两个练习的时间段之间都有至少两 个空闲的时间段让他休息。则小明一共有()种选择时间段的方案。
    A 31
    B 18
    C 21
    D 33
    答案: B. 18
    解析:我们可以按以下方式考虑选择的方案:
    选择1个时间段:有7种方式。
    选择2个时间段:首先选择第一个时间段,然后至少跳过两个时间段选择第二个。方案如下: (1,4) ,(1,5) ,(1,6) ,(1,7) ,(2,5), (2,6) ,(2,7) ,(3,6) ,(3,7) ,(4,7)。一共10种方式。
    .选择3个时间段:只有一种方案,即(1,4,7)。
    选择4个或更多的时间段是不可能的,因为不可能在每两个时间段之间都有两个空闲时间段。
    所以总的选择方案是 7 + 10 + 1 = 18。

  5. 以下关于高精度运算的说法错误的是()
    A 高精度计算主要是用来处理大整数或需要保留多位小数的运算
    B 大整数除以小整数的处理的步骤可以是,将被除数和除数对齐,从左到右逐位尝试将除数乘以某个数,通过减法得到新的被除数,并累 加商
    C 高精度乘法的运算时间只与参与运算的两个整数中长度较长者的位数有关
    D 高精度加法运算的关键在于逐位相加并处理进位
    答案: C.
    解析:高精度乘法的运算时间与两个整数的位数都有关,而不仅仅是长度较长者的位数。

  6. 后缀表达式 “ 6 2 3 + - 3 8 2 / + * 2 ^ 3 + ” 对应的中缀表达式是()
    A ((6-(2+3))(3+8/2))^2+3
    B 6-2+3
    3+8/2^2+3
    C (6-(2+3))((3+8/2)^2)+3
    D 6-((2+3)
    (3+8/2))^2+3
    答案: A.
    解析
    后缀表达式也称为逆波兰表达式,可以通过栈来转换为中缀表达式。根据后缀表达式的规则,将数字和运算符依次入栈,直到遇到运算符时将栈顶的两个数字弹出并进行运算,然后将结果入栈。重复此过程直到遍历完后缀表达式。上述后缀表达式的转换将得到中缀表达式 ( ( 6 - (2 + 3 ) ) * ( 3 + 8 / 2 ) ) ^ 2 + 3。

  7. 数1010102和1668的和为 ( )
    A (10110000)2
    B (236)8
    C (158)10
    D (A0)16
    答案是 D (A0)16
    解析
    首先将二进制数101010(2)转换为十六进制得到A(16),然后将八进制数166(8)转换为十六进制得到0(16),最后将A和0相加得到A0(16)。

  8. 假设有一组字符{a,b,c,d,e,f},对应的频率分别为5%、9%、 12%、 13%、 16%、45%。请问以下哪个选项是字符a,b,c,d,e,f分别对应的一 组哈夫曼编码?
    A 1111,1110,101,100,110,0
    B 1010,1001,1000,011,010,00
    C 000,001,010,011,10,11
    D 1010,1011,110,111,00,01
    答案是 A:
    解析
    哈夫曼编码的生成过程如下:

  • 首先,我们需要根据给定的字符及其频率创建一个优先队列或堆。
  • 然后,我们从堆中取出两个最小频率的节点,并将它们合并为一个新的节点,其频率为这两个节点的频率之和。新节点成为这两个节 点的父节点。
  • 我们将新节点重新插入堆中。
  • 我们重复上述过程,直到堆中只剩下一个节点。这个节点就是我们的哈夫曼树的根节点。
  • 最后,我们从哈夫曼树的根节点开始,为每个字符分配一个编码。左子树的边表示1,右子树的边表示0。

接下来,我们将按照哈夫曼编码算法的步骤,合并频率最低的两个节点,并继续这个过程,直到得到完整的哈夫曼树。
步骤如下:

  • 合并a(5%)和b(9%),得到新节点ab(14%)。
  • 合并c(12%)和d(13%),得到新节点cd(25%)。
  • 合并ab(14%)和e(16%),得到新节点abe(30%)。
  • 合并cd(25%)和abe(30%),得到新节点abcde(55%)。
  • 最后,合并abcde(55%)和f(45%),得到根节点abcdef(100%)。
    从哈夫曼树中,我们可以为每个字符生成哈夫曼编码。从根节点开始,左子树的边表示1,右子树的边表示0。
    根据这个哈夫曼树,字符的哈夫曼编码如下:
    在这里插入图片描述

a: 1111
b: 1110
c: 101
d: 100
e: 110
f: 0
哈夫曼编码树的左右子树可以互换,所以编码方案并不唯一,但对应字母的编码长度一定唯一,根据 f 的编码长度,排除法可知选A

  1. 给定一棵二叉树,其前序遍历结果为: ABDECFG,中序遍历结果为: DEBACFG。请问这棵树的正确后序遍历结果是什么?
    A EDBGFCA
    B EDBGCFA
    C DEBGFCA
    D DBEGFCA
    答案: A
    这道题要求我们根据二叉树的前序遍历和中序遍历结果来确定其后序遍历的结果。
    给定:
    前序遍历: ABDECFG
    中序遍历: DEBACFG
    解析:
  • 从前序遍历中,我们知道A是根节点。
  • 在中序遍历中, A之前的部分DEB是左子树, A之后的部分CFG是右子树。
  • 对于左子树DEB,从前序遍历中我们知道B是左子树的根节点。
  • 在中序遍历中, B之前的部分DE是B的左子树。
  • 对于左子树DE,从前序遍历中我们知道D是左子树的根节点, E是D的右子节点。
  • 对于右子树CFG,从前序遍历中我们知道C是右子树的根节点。
  • 在中序遍历中, C之后的部分FG是C的右子树。
  • 对于右子树FG,从前序遍历中我们知道F是右子树的根节点, G是F的右子节点。
    根据上述分析,我们可以得到以下二叉树结构:
    [图片]

后序遍历:左子树 -> 右子树 -> 根节点
对于上述二叉树,后序遍历的结果为: EDBGFCA
所以,正确答案是 A EDBGFCA。

  1. 考虑一个有向无环图,该图包含4条有向边: (1,2),(1,3),(2,4)和(3,4)。以下哪个选项是这个有向无环图的一个有效的拓扑排序?
    A 4,2,3,1
    B 1,2,3,4
    C 1,2,4,3
    D 2,1,3,4

答案: B
解析:
拓扑排序是一个有向无环图中节点的线性排序,使得对于每一条有向边 (u, v),节点 u 在排序中都出现在节点 v 之前。在给定的有向无环图中,节点1必须在节点2和节点3之前出现,因此一个有效的拓扑排序是1, 2, 3, 4。

  1. 在计算机中,以下哪个选项描述的数据存储容量最小()
    A 字节 (byte)
    B 比特 (bit)
    C 字 (word)
    D 千字节(kilobyte)
    答案: B
    解析
    在计算机中,数据存储容量的基本单位是比特 (bit)。以下是各个选项的描述:
    A. 字节 (byte) - 通常包含8个比特 (bit)。
    B. 比特 (bit) - 基本单位,可以是0或1。
    C. 字 (word) - 它的大小取决于特定的计算机架构,但通常是16、32或64位。
    D. 千字节 (kilobyte) - 通常包含1024字节或8192比特。
    因此,描述的数据存储容量从小到大为:比特 (bit) < 字节 (byte) < 字 (word) < 千字节 (kilobyte)。
    所以,正确答案是 B. 比特 (bit),因为它描述的数据存储容量最小。

  2. 一个班级有10个男生和12个女生。如果要选出一个3人的小组,并且小组中必须至少包含1个女生,那么有多少种可能的组合?()
    A 1420
    B 1770
    C 1540
    D 2200
    答案: A
    解析
    可以使用组合数学的方法来解决这个问题。首先计算所有选出3个人的组合数:C(22, 3)。然后计算不包含女生的组合数:C(10, 3)。最后,总的组合数减去不包含女生的组合数即可得到包含至少1个女生的组合数:C(22, 3) - C(10, 3) = 1420。

  3. 以下哪个不是操作系统?()
    A Linux
    B Windows
    C Android
    D HTML
    答案: D
    操作系统是管理计算机硬件和软件资源的软件,它为计算机程序提供服务。
    A. Linux - 是一个操作系统。
    B. Windows - 是一个操作系统。
    C. Android - 是一个操作系统,主要用于移动设备。
    D. HTML - 是一种用于描述网页的标记语言,不是操作系统。
    所以,正确答案是 D. HTML,因为它不是操作系统。

阅读程序
阅读程序1

01 #include<iostream>
02 #include<cmath>
03 using namespace std;
04
05 double f(double a,double b,double c){
06     double s=(a+b+c)/2;
07     return sqrt(s*(s-a)*(s-b)*(s-c));
08 }
09
10 int main(){
11    cout.flags(ios::fixed);
12    cout.precision(4);
13
14     int a,b,c;
15    cin>>a>>b>>c;
16    cout<<f(a,b,c)<<endl;
17    return 0;
18 }

假设输入的所有数都为不超过1000的正整数,完成下面的判断题和单选题:

以下是对程序的判断题和单选题的解析:
判断题:
16. (2分) 当输入为“2 2 2”时,输出为“1.7321” (√)
解析:输入为"2 2 2",这是一个等边三角形,根据Heron’s Formula计算面积,输出应该为1.7321,所以答案是正确的。
17. (2分) 将第7行中的“(s - b) * (s - c)”改为“(s - c) * (s - b)”不会影响程序运行的结果(√)
解析:两者是等价的,因为乘法满足交换律,所以不会影响程序的运行结果。
18. (2分) 程序总是输出四位小数。(×)
解析:由于第11和第12行设置了输出格式为固定的,并且精度为4,所以当输入数据满足构成三角形条件时,输出总是四位小数。但是如果 输入数据不满足构成三角形的条件时(任意两边之和大于第三边),sqrt的结果是 “nan”,所以输出不总是四位小数。
单选题:
19. 当输入为“3 4 5”时,输出为(A)
答案:A. “6.0000”
解析:根据输入的边长,程序使用Heron’s Formula计算三角形的面积,因此输出为6.0000。
20. 当输入为“5 12 13”时,输出为(B)
答案:B. “30.0000”
解析:根据输入的边长,程序使用Heron’s Formula计算三角形的面积,因此输出为30.0000。

阅读程序2

01 #include<iostream>
02 #include<vector>
03 #include<algorithm>
04 using namespace std;
05
06 int f(string x,string y){
07     int m=x.size();
08     int n=y.size();
09     vector<vector<int>>v(m+1,vector<int>(n+1,0));
10    for(int i=1;i<=m;i++){
11        for(int j=1;j<=n;j++){
12             if(x[i-1]==y[j-1]){
13                 v[i][j]=v[i-1][j-1]+1;
14             }else{
15                 v[i][j]=max(v[i-1][j],v[i][j-1]);
16             }
17         }
18     }
19     return v[m][n];
20 }
21
22 bool g(string x,string y){
23     if(x.size() != y.size()){
24         return false;
25     }
26     return f(x+x,y)==y.size();
27 }
28
29 int main(){
30     string x,y;
31     cin>>x>>y;
32     cout<<g(x,y)<<endl;
33     return 0;
34 }

判断题:
21. f函数的返回值小于等于min(n,m)。 (√)
答案:正确。
解析: f 函数返回的是两个字符串的最长公共子序列的长度,这个长度肯定不会超过两个字符串中较短的那个的长度。
22. f函数的返回值等于两个输入字符串的最长公共子串的长度。 (×)
解析:×。f函数计算的是最长公共子序列的长度,而不是最长公共子串。最长公共子序列可以不连续,但最长公共子串必须是连续的。
23. 当输入两个完全相同的字符串时,g函数的返回值总是true。 (√)
解析:正确。如果两个字符串完全相同,它们的最长公共子序列的长度将等于其中一个字符串的长度,因此g函数会返回true。
单选题:
24. 将第19行中的“v[m][n]”替换为“v[n][m]”,那么该程序()。
A. 行为不变
B. 只会改变输出
C. 一定非正常退出
D. 可能非正常退出

答案:D. 可能非正常退出
解析:因为 根据条件:m==2n,返回的元素从 v[2n][n] 变成了v[n][2n] ,二维的vector内存是不连续的, 列可能会越界。
25. 当输入为“csp-j p-jcs”时,输出为()。
A. “0”
B. “1”
C. “T”
D. “F”
答案:B. “1”
解析:这里我们要检查字符串“p-jcs”是否可以通过循环移位得到“csp-j”。通过 g 函数,我们会检查 f(“csp-jcsp-j”, “p-jcs”) 是否等于 “p-jcs”.size() 。最长公共子序列是"p-jcs",长度为5。

  1. 当输入为“csppscspsccp”时,输出为()。
    A. “T”
    B. “F”
    C. “0”
    D. “1”
    答案:A. “1”
    解析:这里我们要检查字符串“spsccp”是否可以通过移位得到“csppsc”。通过 g 函数,我们会检f(“csppsccsppsc”, “spsccp”) 是否等 于 “spsccp”.size() 。最长公共子序列是"spsccp",长度为6,这意味着我们可以得到另一个字符串。

阅读程序3

01 #include <iostream>
02 #include <cmath>
03 using namespace std;
04
05 int solve1(int n){
06     return n*n;
07 }
08
09 int solve2(int n){
10    int sum=0;
11    for(int i=1;i<=sqrt(n);i++){
12         if(n%i==0){
13             if(n/i==i){
14                 sum+=i*i;
15             }else{
16                 sum+=i*i+(n/i)*(n/i);
17             }
18         }
19     }
20     return sum;
21 }
22
23 int main(){
24     int n;
25     cin>>n;
26     cout<<solve2(solve1(n))<<" "<<solve1((solve2(n)))<<endl;
27     return 0;
28 }

假设输入的n是绝对值不超过1000的整数,完成下面的判断题和单选题。

  1. 如果输入的n为正整数, solve2函数的作用是计算n所有的因子的平方和()
    解析: solve2 函数确实计算了输入整数的所有因子的平方和。
    答案:正确。

  2. 第13~14行的作用是避免n的平方根因子i(或n/i)进入第16行而被计算两次()
    解析:当 i 是 n 的平方根时, n/i 也是 i 。为了避免重复计算,我们只计算一次 i 的平方。
    答案:正确。

  3. 如果输入的n为质数, solve2( n)的返回值为n^2+1 ()
    解析:质数的唯一因子是1和它自己。所以, solve2(n) 的返回值是 1^2 + n^2 ,即 n^2 + 1 。
    答案:正确。

  4. 如果输入的n为质数p的平方,那么solve2( n)的返回值为()
    解析:如果 n 是质数 p 的平方,那么它的因子是1, p和p^2。所以, solve2(n) 的返回值是 1^2 + p^2 + p^4 ,即 n^2 + n + 1 。
    答案: B

  5. 当输入为正整数时,第一项减去第二项的差值一定()
    解析:
    第一项是 solve2(solve1(n)) ,第二项是 solve1(solve2(n)) 。
    当 n 大于 1时,代入计算, solve2(solve1(n)) 的结果是 n^4 + n^2 + 1
    solve1(solve2(n)) 的结果是 (n^2 + 1)^2 ,根据完全平方和公式,因为 n是正整数,所以第一项小于第二项;
    当n 等于1时,两项相等,所以选D
    答案: D. 小于等于0且不一定小于0

  6. 当输入为“5”时,输出为()
    解析:输入为5时, solve1(5) 返回25 , solve2(25) 返回1^2 + 5^2 + 25^2 = 651。 solve2(5) 返回1^2 + 5^2 = 26 , solve1(26) 返回676。 所以,输出为"651 676"。
    答案: C. “651 676”
    完善程序
    完善程序1
    (1)(寻找被移除的元素)问题:原有长度为 n+1公差为1等升数列,将数列输到程序的数组时移除了一个元素,导致长度为 n 的开序数组可能不 再连续,除非被移除的是第一个或最后之个元素。需要在数组不连续时,找出被移除的元素。试补全程序。

01 #include <iostream
02 #include <vector>
03
04 using namespace std;
05
06 int find missing(vector<int>& nums) {
07 int left = 0, right = nums.size() - 1;
08while (left < right){
09   int mid = left + (right  left) / 2;
10   if (nums[mid] == mid+ ① ) {
11        ②;
12    }else{
13      ③
14    }
15   }
16  return ④;
17 }
18
19 int main() {
20    int n;
21 cin >> n;
22 vector<int> nums(n);
23 for (int i= 0; i< n; i++) cin >> nums[i];
24 int missing_number = find_missing(nums);
25 if_(missing_number == ⑤ ) {
26     cout << "Sequence is consecutive" << endl;
27 }else{
28    cout << "Missing number is " << ,missing numbeer << endl;
29 }
30 return 0;
31 }

33 ①处应填()
A. 1 B.nums[0] C.right D.left
34 ②处应填()
A. left=mid+1 B.right=mid-1 C.right=mid D.left=mid
35 ③处应填()
A.left=mid+1 B.right=mid-1 C.right=mid D.left=mid
36 ④处应填()
A.left+nums[0] B.right+nums[0] C.mid+nums[0] D.right+1
37 ⑤处应填()
A.nums[0]+n B.nums[0]+n-1 C.nums[0]+n+1 D.nums[n-1]

【程序解析】本题考察二分法。在本程序中find_missing函数就是利用二分法来找到一个长度为n的数组中不连续的位置,从而找出被移除 元素的值。只需通过二分找到从左往右第一处使得nums[i]不为nums[0]+i的的位置,那么在数组中被移除的数就是nums[0]+i。
33. ①处应填()
A. 1 B.nums[0] C.right D.left
【答案】 B
【解析】若数组连续, 一定有nums[i]==nums[0]+i,所以只需通过二分找到第一处使得nums[i]不为nums[0]+i的的位置即可。因此二分的判断条件是nums[mid]==nums[0]+mid。选B

  1. ②处应填()
    A. left=mid+1 B.right=mid-1 C.right=mid D.left=mid
    【答案】A
    【解析】若满足33所填的判断条件,则说明此时的mid猜小了,实际不连续位置(第一处使得nums[i]不等于nums[0]+i的位置) 一定在mid之后,所以需要更新二分的左端点,并更新为mid+1,因此选择A

  2. ③处应填()
    A.left=mid+1 B.right=mid-1 C.right=mid D.left=mid
    【答案】 C
    【解析】若不满足33所填的判断条件,就说明mid有可能猜大了,实际不连续位置(第一处使得nums[i]不等于nums[0]+i的位置) 一定不在 mid之后,可以等于mid。因此需要更新二分右端点,并且更新为mid。

  3. ④处应填()
    A.left+nums[0] B.right+nums[0]
    C.mid+nums[0] D.right+1
    【答案】A
    【解析】左端点left才能表示最终二分找到的答案(也即不连续位置),因此最终被移除的数就是left+nums[0]。首先很容易排除D,然 后因为mid只出现在二分的过程中,而且mid的定义也在while里,也很容易排除C。
    可能的问题:这里为何选择A而不选择B,事实上我们二分模板中的书写习惯是return left。在一些情况下return right会出现问题,但在 本题中实际上最后一定是left==right,所以理论上填B也可以。

  4. ⑤处应填()
    A.nums[0]+n B.nums[0]+n-1
    C.nums[0]+n+1 D.nums[n-1]
    【答案】 D
    【解析】当 n个数字连续时,最终我们会得到, left=n-1 ,right=n-1。由36所填代码,我们返回的数字就是nums[0]+n-1与不连续位置出现在 第n个数字返回的数值相同。因此我们需要对这两种情况进行讨论,如果n个数字连续,会满足nums[n-1]==nums[0]+n-1,如果是刚好不连续位置在第n个数的话不会使得这个式子成立。因此如果返回数字等于nums[n-1]的话,就说明原来n个数连续。故而选择D。

完善程序2
(编辑距离)给定两个字符串,每次操作可以选择删除(Delete)、插入(Insert)、替换(Replace), 一个字符,求将第一个字符串转 换为第二个字符串所需要的最少操作次数。
试补全动态规划算法。

01 #include <iostream>
02 #include <string>
03 #include <vector>
04 using namespace std;
05 
06 int min(int x, int y, int z) {
07   return min(min(x, y), z);
08 } 
09
10 int edit_dist_dp(string str1, string str2) {
11    int m = str1.length();
12    int n = str2.length();
13    vector<vector<int>> dp(m + 1, vector<int>(n + 1));
14   
15    for (int i = 0; i <= m; i++) {
16          for (int j = 0; j <= n; j++) {
17                  if (i == 0)
18                         dp[i][j] = ①;
19                  else if (j == 0)
20                         dp[i][j] = ②;
21                  else if ( ③ )
22                         dp[i][j] = ④;
23                  else
24                         dp[i][j] = 1 + min(dp[i][j - 1], dp[i - 1][j], ⑤);
25           }
26    }
27    return dp[m][n];
28 }
29
30 int main() {
31    string str1, str2;
32    cin >> str1 >> str2;
33    cout << "Minimum number of operations: "
34           << edit_dist_dp(str1, str2) << endl;
35    return 0;
36 }

38 ①处应填()
A.j B.i C.m D.n
39 ②处应填()
A.j B.i C.m D.n
40 ③处应填()
A. str1[i-1]==str2[j-1] B. str1[i]==str2[j]
C. str1[i-1]!=str2[j-1] D. str1[i]!=str2[j]
41 ④处应填()
A. dp[i-1][j-1]+1 B. dp[i-1][j-1]
C. dp[i-1][j] D. dp[i][j-1]
42 ⑤处应填()
A. dp[i][j] + 1 B. dp[i-1][j-1]+1
C. dp[i-1][j-1] D. dp[i][j]

【程序解析】先阅读 main 函数,可以得知代码读入了两个字符串之后输出了 edit_dist_dp 的返回值,因此重点关注 edit_dist_dp 函数;
11-13 行定义了 n 为 str1 的长度,m 为 str2 的长度, 一个二维的 vector(可以当成二维数组),dp[0…m][0…n];
15-26 行为 dp 过程;
27 行为返回 dp[n][m],看完这一行就应该明白 dp 数组的含义,之后通过 dp 状态将 15-26 行的空填出来;
dp[n][m] 表示将 str1 长度为 n 的前缀变成 str2 长度为 m 的前缀需要的最少步数,特别注意 str1, str2 是 string,下标范围分别是 [0…m-1] 与 [0…n-1]。
38. ①处应填()
A.j B.i C.m D.n
【答案】A
【解析】考察 dp[0][j] 的值,根据阅读得到的 dp 数组的含义, dp[0][j] 表示 str1 长度为 0 的前缀(空字符串)变成 str2 长度为 j 的前缀 的最少步数,这里明显最少在空串内添加 str2 的前 j 个字符,因此填 j选 A 选项

  1. ②处应填()
    A.j B.i C.m D.n
    【答案】 B
    【解析】考察 dp[i][0] 的值,根据阅读得到的 dp 数组的含义, dp[i][0] 表示 str1 长度为 i 的前缀变成str2 长度为 0 的前缀(空字符串)的最少步数,这里明显最少是将 str1 的前 i个字符全部删除,因此填 i 选 B 选项

  2. ③处应填()
    A. str1[i-1]==str2[j-1] B. str1[i]==str2[j] C. str1[i-1]!=str2[j-1] D. str1[i]!=str2[j]
    【答案】A
    【解析】考察编辑距离 dp 转移,需要阅读 22-24 行的代码可知这里应该是两个字符相等不需要操作的情况,也就是 str1 的第 i个字符与 str2 的第 j 个字符相等的情况,但是要特别注意的是这一问埋了大坑, str1 的第 i个字符是str1[i-1],不要跳进去了,选 A

  3. ④处应填()
    A. dp[i-1][j-1]+1 B. dp[i-1][j-1] C. dp[i-1][j] D. dp[i][j-1]
    【答案】 B
    【解析】40题时已经说过,如果两个字符相等的话,不需要操作,因此将 str1 前 i个字符变成 str2 前 j 个字符需要的最少步数就与将 str1 前 i-1 个字符变成 str2 前j-1 个字符是一样的,填 dp[i-1][j-1],选 B

  4. ⑤处应填()
    A. dp[i][j] + 1 B. dp[i-1][j-1]+1 C. dp[i-1][j-1] D. dp[i][j]
    【答案】 C
    【解析】这里有一个在上面定义的 min 函数,功能是对三个整数求最小值,观察第 24 行 dp[i][j] = 1 + min(dp[i][j – 1], dp[i – 1][j]) 由 前面的 1 + 可知这里进行了一次操作,那么dp[i][j – 1] 就对应着插入, dp[i – 1][j] 对应着删除,剩下要填的就是替换了,填 dp[i-1][j-1],选 C

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值