2.5.2 真题
强化讲义 · 原始转写 · 原书检索 · 文字用于定位,公式与图表请回原页核验 · 本次导入快照
## 2.5.2 真题
【2010年42 题】(13 分)设将n(n>1)个整数存放到一维数组R中。试设计一个在时间和空间两方面都尽可能高效的算法。将 R 中保存的序列循环左移p(0 < p < n)个位置,即将R 中的数据由(Xx0, X1, . . ., Xn−1)变换为(Xp, Xp+1,. . ., Xn−1, X0, Xx1, . .,Xp−1)。要求: (1)给出算法的基本设计思想。(2)根据设计思想,采用C、C++或Java 语言描述算法,关键之处给出注释。(3)说明你所设计算法的时间复杂度和空间复杂度。
<!-- page 48 -->
【2011年42题】(15分)—个长度为L(L≥1)的升序序列S,处在第「L/21个位置的数称为 S 的中位数。例如,若序列S1 = (11,13,15, 17,19),则S1 的中位数是 15,两个序列的中位数是含它们所有元素的升序序列的中位数。例如,若 S2= (2,4,6,8,20),则S1 和S2的中位数是11。现在有两个等长升序序列A和B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数。要求:(1)给出算法的基本设计思想。
(2)根据设计思想,采用C、C++或Java 语言描述算法,关键之处给出注释。(3)说明你
<!-- page 49 -->
【2013 年41 题】 (13 分)已知—个整数序列 A =(a0, a1,., an−1),其中 0 ≤ ai < n(0 ≤ i< n)。若存在 ap1 = ap2 =... = apm = x 且 m > n/2 (0 ≤ pk < n, 1 ≤ k ≤ m),则称 x 为 A 的主元素。例如 A = (0, 5, 5, 3, 5, 7, 5, 5),则 5 为主元素;又如 A = (0, 5, 5, 3, 5, 1,5, 7),则 A 中没有主元素。假设A中的n个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找出A的主元素。若存在主元素,则输出该元素;否则输出-1。要求:(1)给出算法的基本设计思想。(2)根据设计思想,采用C、C++或Java 语言描述算法,关键之处给出注释。(3)说明你所设计算法的时间复杂度和空间复杂度。
<!-- page 50 -->
【2016 年43题】 (13 分)已知由 n(n ≥ 2)个正整数构成的—个集合A= {ak | 0 ≤ k <n},将其划分为两个不相交的子集 A1 和 A2,元素个数分别是n1 和 n2,A1 和 A2 中元素之和分别为 S1 和 S2。设计一个尽可能高效的划分算法,满足 |n1 - n2| 最小且 |S1 - S2| 最大。要求:(1)给出算法的基本设计思想。(2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。(3)说明你所设计算法的平均时间复杂度和空间复杂度。
<!-- page 51 -->
【2018年41题】(13 分)给定一个含n(n≥1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。例如,数组{-5,3,2,3}中未出现的最小正整数是1;数组{1,2,3}中未出现的最小正整数是4。要求:(1)给出算法的基本设计思想。(2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。(3)说明你所设计算法的时间复杂度和空间复杂度。 X
<!-- page 52 -->
【2020年41题】(13 分)定义三元组(a,b,c)(a,b,c均为正数)的距离D=|a− b|+|b - c + |c - a|。给定3 个非空整数集合 S1、S2 和S3,按升序分别存储在3 个数组中。请设计一个尽可能高效的算法,计算并输出所有可能的三元组(a,b,c)(a∈S1,b∈S2,c∈S3) 中的最小距离。例如 S1 = {-1,0,9},S2 = {-25, -10,10, 11},S3 = {2,9,17,30,41},则最小距离为2,相应的三元组为(9,10,9)。要求:(1)给出算法的基本设计思想。(2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。(3)说明你所设计算法的时间复杂度和空间复杂度。
<!-- page 53 -->
【2025 年 41 题】(13 分)有两个长度均为 n 的一维整型数组 A[n]、res[n],计算 A[i]与A[j](0≤i≤j≤n-1) 乘积的最大值,并将其保存到 res[i]中。若 A[] = {1, 4, -9, 6},则得到 res[] ={6, 24, 81, 36}。现给定数组 A,请设计时间空间上尽可能高效的算法 CalMulMax,求 res 中各元素的值。函数原型为:void CalMulMax(int A[], int res[], int n)。(1)给出算法的基本思想。(4 分)(2)用C/C++描述算法关键之处给出注释。(7 分) (3)说明时间、空间复杂度。(2 分) 当计
<!-- page 54 -->
## 2.6 章节答案
## 2.6.1 习题
## \*习题2-1
(13 分)已知升序数组 A含有n 个整数,求是否存在值为x的元素,存在返回数组下标,不存在则返回-1。设计一个在时间上尽可能高效的算法实现该功能。例:A={1,2,3,7,8,11,15},n = 7,x = 8,则返回数组下标为 4。 (1)给出算法的基本设计思想。 (2) 根据设计思想,采用C、C++或Java语言描述算法,关键之处给出注释。(3)说明你所设计算法的时间复杂度和空间复杂度。
<table><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>做题思路</td><td rowspan=1 colspan=1>时间复杂度</td><td rowspan=1 colspan=1>空间复杂度</td><td rowspan=1 colspan=1>得分</td></tr><tr><td rowspan=1 colspan=1>暴力解</td><td rowspan=1 colspan=1>枚举</td><td rowspan=1 colspan=1>O(n)</td><td rowspan=1 colspan=1>0(1)</td><td rowspan=1 colspan=1>11</td></tr><tr><td rowspan=1 colspan=1>优化解</td><td rowspan=1 colspan=1>折半查找</td><td rowspan=1 colspan=1>O(logn)</td><td rowspan=1 colspan=1>O(1)</td><td rowspan=1 colspan=1>13</td></tr></table>
## 【解法1】暴力解:枚举
(1)遍历一趟数组,依次判断每个元素是否为x,是则返回数组下标,如果遍历完还没找到则返回-1。(2)伪代码如下:
int ans(int A[], int n, int x)
{
for (int i=0; i<n; i++)
if (A[i]==x) return i;
return -1;
}
(3) 时间复杂度:O(n)空间复杂度:O(1)
## 【解法2】优化解:折半查找
(1)以0、n-1 分别作为左、右边界对升序数组 A折半查找,查找到x则返回数组下标,查找失败则返回-1。(2)伪代码如下:
<!-- verified-by-hand -->
> [!success] 已结合原文第 54 页及 Markdown 上下文人工校对
> while 缺少复合语句花括号,return -1 和函数闭合花括号被移到函数外。
int B_Search(int A[], int L, int R, int x)
{
while (L <= R)
{
int mid = L + (R - L) / 2;
if (x == A[mid]) return mid;
if (x < A[mid]) R = mid - 1;
else L = mid + 1;
}
return -1;
}
<!-- page 55 -->
(3)时间复杂度:O(logn)空间复杂度:O(1)
## \*习题2-2
(13 分)已知两个整数升序数组 A和B,他们的元素数分别为n和 m,请将他们合并成一个新的升序数组C,并输出C 数组。设计一个尽可能高效的算法实现该功能。例:A={1,2,7}, n = 3,B = {3, 4, 5, 10},m = 4,则 C = {1, 2, 3, 4, 5, 7, 10}。 (1) 给出算法的基本设计思想。(2)根据设计思想,采用C、C++或Java 语言描述算法,关键之处给出注释。(3)说明你所设计算法的时间复杂度和空间复杂度。
<table><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>做题思路</td><td rowspan=1 colspan=1>时间复杂度</td><td rowspan=1 colspan=1>空间复杂度</td><td rowspan=1 colspan=1>得分</td></tr><tr><td rowspan=1 colspan=1>暴力解</td><td rowspan=1 colspan=1>快速排序</td><td rowspan=1 colspan=1>O((m + n)log(m-</td><td rowspan=1 colspan=1>-O(m + n)</td><td rowspan=1 colspan=1>11</td></tr><tr><td rowspan=1 colspan=1>优化解</td><td rowspan=1 colspan=1>多指针法</td><td rowspan=1 colspan=1>O(m +n)</td><td rowspan=1 colspan=1>O(m + n)</td><td rowspan=1 colspan=1>13</td></tr></table>
## 【解法1】暴力解:快速排序
(1)先开辟一个足够大的新数组C,将数组 A和数组B 的所有元素依次放入数组C 中,然后对整个C 数组进行快速排序,使其成为升序数组。(2)伪代码如下: 1
//快速排序函数
void Qsort(int A[], int L, int R)
{
if (L >= R) return; //区间≤1,返回
int i = L, j = R;
int pivot = A[L]; //选首元素为基准
//不断交换左边比pivot 大的数和右边比 pivot 小的数
while (i < j) {
while (i < j && A[j] >= pivot) j--; // 从右找第—个 <pivot 的数
while (i < j && A[i] <= pivot) i++; // 从左找第—个 >pivot 的数
if (i < j) swap(A[i], A[j]);
}
//将基准值A[L] 与A[i]交换
swap(A[L], A[i]);
//递归处理左右两个子区间
Qsort(A, L, i - 1);
Qsort(A, i + 1, R);
}
int ans(int A[], int n, int B[], int m)
{
int C[m + n];
for (int i = 0; i < n; i++)
C[i] = A[i];
for (int i = 0; i < m; i++)
C[n + i] = B[i];
Qsort(C, 0, m + n - 1);
输出数组C
}
<!-- page 56 -->
(3) 时间复杂度:O((m + n)log(m + n)) 空间复杂度:O(log(m + n))
## 【解法2】优化解:多指针法
(1)设置三个指针i、j、k 分别指向数组 A、B、C 的起始位置。比较 A[i]和 B[]的值,将较小的元素放入C[k],并将对应的指针(i或j)和k都后移一位。重复此过程,直到其中一个数组遍历完毕。最后,将另一个数组中剩余的元素直接复制到C数组的末尾。(2)伪代码如下:
void Merge(int A[], int n, int B[], int m)
{
int C[m + n];
int i = 0, j = 0, k = 0;
//比较并合并
while (i < n && j < m)
{
if (A[i] < B[j]) C[k++] = A[i++];
else C[k++] = B[j++];
}
// 复制剩余元素
while (i < n) C[k++] = A[i++];
while (j < m) C[k++] = B[j++];
输出数组C
}
3)时间复杂度:O(m + n)空间复杂度:O(m + n)
## \*习题2-3
(15 分)已知数组A 中有n 个非负元素,每个元素绝对值< n,其中只有一个数重复出现过,请输出这个数,否则输出-1。设计一个时间上尽可能高效的算法实现该功能。例:n=6,A = {1, 2, 5, 2, 4, 3},则 2 重复出现,输出 2。 (1)给出算法的基本设计思想。 (2) 根据设计思想,采用C、C++或Java 语言描述算法,关键之处给出注释。(3)说明你所设计
<!-- page 57 -->
<table><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>做题思路</td><td rowspan=1 colspan=1>时间复杂度</td><td rowspan=1 colspan=1>空间复杂度</td><td rowspan=1 colspan=1>得分</td></tr><tr><td rowspan=1 colspan=1>暴力解</td><td rowspan=1 colspan=1>枚举法</td><td rowspan=1 colspan=1>O(n2)</td><td rowspan=1 colspan=1>0(1)</td><td rowspan=1 colspan=1>11</td></tr><tr><td rowspan=1 colspan=1>暴力解</td><td rowspan=1 colspan=1>快速排序</td><td rowspan=1 colspan=1>O(nlogn)</td><td rowspan=1 colspan=1>O(logn)</td><td rowspan=1 colspan=1>13</td></tr><tr><td rowspan=1 colspan=1>优化解</td><td rowspan=1 colspan=1>散列表</td><td rowspan=1 colspan=1>O(n)</td><td rowspan=1 colspan=1>O(n)</td><td rowspan=1 colspan=1>15</td></tr></table>
## 【解法1】暴力解:枚举法
(1) 两层循环i和j枚举,判断A[i]和A[j]是否相等(i< j),如果相等则说明这个数重复出现过,输出A[i]。如果没发现相等的则输出-1。(2)伪代码如下:
int ans(int A[], int n)
{
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++)
if (A[i] == A[j]) return A[i];
return -1;
}
(3)时间复杂度:O(n²) 空间复杂度:O(1)
## 【解法2】暴力解:快速排序
(1)先将数组A快速排序后,在排序好的数组中查找是否有重复元素,然后遍历C数组判断如果某个元素和他前一个元素相等说明有重复元素,输出。如果最终都没有发现发现有重复元素,则输出-1。(2)伪代码如下:
<!-- verified-by-hand -->
> [!success] 已结合原文第 57 页及 Markdown 上下文人工校对
> 对照原文第57-58页校正:注释里 OCR 错字(第—论/第个 -> 第一个);代码本身已正确
// 快速排序函数
void Qsort(int A[], int L, int R)
{
if (L >= R) return; // 区间≤1,返回
int i = L, j = R;
int pivot = A[L]; // 选首元素为基准
// 不断交换左边比 pivot 大的数和右边比 pivot 小的数
while (i < j)
{
while (i < j && A[j] >= pivot) j--; // 从右找第一个 <pivot 的数
while (i < j && A[i] <= pivot) i++; // 从左找第一个 >pivot 的数
if (i < j) swap(A[i], A[j]);
}
// 将基准值 A[L] 与 A[i] 交换
swap(A[L], A[i]);
// 递归处理左右两个子区间
Qsort(A, L, i - 1);
Qsort(A, i + 1, R);
}
int ans(int A[], int n)
{
Qsort(A, 0, n - 1);
for (int i = 1; i < n; i++)
if (A[i] == A[i - 1]) return A[i];
return -1;
}
<!-- page 58 -->
(3)时间复杂度:O(nlogn)空间复杂度:O(logn)
## 【解法3】优化解:散列表
(1)设置count数组表示某个数出现的次数,循环遍历数组A并更新count数组,访问A[i]时如果发现count[A[i]]已经>0说明之前A[i]已经出现过,输出A[i]。如果最终都没有发现有重复元素,则输出-1。(2)伪代码如下:
int ans(int A[], int n)
{
int count[n] = {0};
for (int i = 0; i < n; i++)
{
if (count[A[i]] > 0) return A[i];
count[A[i]]++;
}
return -1;
}
(3)时间复杂度:O(n)空间复杂度:O(n)
## 习题2-4
(15 分)已知整数数组 A含有 n 个不相等的整数(n 为奇数,且数组 A 中每个元素的绝对值≤ n)。设计一个时间上尽可能高效的算法,求数组 A的中位数。例:n=5,A={-3, 0, 4, -2,3},则中位数为0。(1)给出算法的基本设计思想。(2)根据设计思想,采用C、C++或Java 语言描述算法,关键之处给出注释。(3)说明你所设计算法的时间复杂度和空间复杂度。
<table><tr><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>做题思路</td><td rowspan=1 colspan=1>时间复杂度</td><td rowspan=1 colspan=1>空间复杂度</td><td rowspan=1 colspan=1>得分</td></tr><tr><td rowspan=1 colspan=1>暴力解</td><td rowspan=1 colspan=1>枚举法</td><td rowspan=1 colspan=1>O(n2)</td><td rowspan=1 colspan=1>0(1)</td><td rowspan=1 colspan=1>11</td></tr><tr><td rowspan=1 colspan=1>暴力解</td><td rowspan=1 colspan=1>快速排序</td><td rowspan=1 colspan=1>O(nlogn)</td><td rowspan=1 colspan=1>O(logn)</td><td rowspan=1 colspan=1>13</td></tr><tr><td rowspan=1 colspan=1>优化解</td><td rowspan=1 colspan=1>散列表</td><td rowspan=1 colspan=1></td><td rowspan=1 colspan=1>O(n)</td><td rowspan=1 colspan=1>15</td></tr><tr><td rowspan=1 colspan=1>优化解</td><td rowspan=1 colspan=1>多指针法</td><td rowspan=1 colspan=1>O(n)</td><td rowspan=1 colspan=1>O(logn)</td><td rowspan=1 colspan=1>15</td></tr></table>
<!-- page 59 -->