数据结构考了这么一题,写出来了,但似乎不是最优解,有点小遗憾。这里把题目整理一下,供大家参考。
题目
一维数组
A
[
m
+
n
]
A[m+n]
A[m+n]中存放着两个线性表:
[
a
1
,
a
2
,
a
3
,
.
.
.
,
a
m
]
[a_1,a_2,a_3,...,a_m]
[a1,a2,a3,...,am]和
[
b
1
,
b
2
,
b
3
,
.
.
.
b
n
]
[b_1,b_2,b_3,...b_n]
[b1,b2,b3,...bn],顺序为
a
a
a在前
b
b
b在后。设计算法,将线性表
a
,
b
a,b
a,b调换顺序,使得数组
A
A
A结果如下:
A
=
[
b
1
,
b
2
,
.
.
.
,
b
n
,
a
1
,
a
2
,
.
.
.
a
m
]
A=[b_1,b_2,...,b_n,a_1,a_2,...a_m]
A=[b1,b2,...,bn,a1,a2,...am]
要求:
- 空间复杂度为 O ( 1 ) O(1) O(1),时间复杂度尽可能高效
- 采用C或C++语言描述算法,关键之处给出注释
思路一
将线性表 b b b中的元素逐个前移至线性表 a a a前,每移动一个 b b b中的元素都要将 a a a整体后移一位,故时间复杂度为 O ( m n ) O(mn) O(mn),具体实现如下:
void exchange(int *A,int m,int n){
//a对应的下标范围0~m-1,b对应的下标范围m~m+n-1
for(int i=m;i<m+n;i++){
//每次选取一个b中的元素
int temp=A[i];
for(int j=i;j>i-m;j--){
//将a中的元素后移一位
A[j]=A[j-1];
}
A[i-m]=temp;
}
}
代码很简洁,但是时间复杂度还是比较高的,主要是 a a a做了太多移位的操作。
思路二
特此声明,这个思路来自我的朋友,交流之后受他启发,将这个思路在此整理一下。
步骤:
- 将整个数组 A A A翻转 A = [ b n , b n − 1 , . . . , b 1 , a m , a m − 1 , . . . , a 1 ] A=[b_n,b_{n-1},...,b_1,a_m,a_{m-1},...,a_1] A=[bn,bn−1,...,b1,am,am−1,...,a1]
- 将线性表 b b b翻转 A = [ b 1 , b 2 , . . . , b n , a m , a m − 1 , . . . , a 1 ] A=[b_1,b_2,...,b_n,a_m,a_{m-1},...,a_1] A=[b1,b2,...,bn,am,am−1,...,a1]
- 将线性表 a a a翻转 A = [ b 1 , b 2 , . . . , b n , a 1 , a 2 , . . . , a m ] A=[b_1,b_2,...,b_n,a_1,a_2,...,a_m] A=[b1,b2,...,bn,a1,a2,...,am]
是不是很妙!
void swap(int &a,int &b){
//交换元素操作
int tmp=a;
a=b;
b=tmp;
}
void reverse(int *A,int start,int end){
//翻转线性表操作,给出起始位置和结束位置,范围[start,end]闭区间
for(int i=start,j=end;i<j;i++,j--){
swap(A[i],A[j]);
}
}
void exchange(int *A,int m,int n){
//0~m-1存a,m~m+n-1存b
//时间复杂度O((m+n)/2)
reverse(A,0,m+n-1);
reverse(A,0,n-1);
reverse(A,n,m+n-1);
}
附个测试代码:
const int M=4,N=3;
int main(){
int A[M+N]={0,2,4,6,1,3,5};
exchange(A,M,N);
for(int i=0;i<M+N;i++){
cout<<A[i]<<' ';
}
return 0;
//[1,3,5,0,2,4,6]
}
这里线性表的翻转操作的时间复杂度为 O ( n 2 ) O(\frac{n}{2}) O(2n),所以整体算法的时间复杂度为 O ( m + n 2 + m 2 + n 2 ) = O ( m + n ) O(\frac{m+n}{2}+\frac{m}{2}+\frac{n}{2})=O(m+n) O(2m+n+2m+2n)=O(m+n)。
平时做过挺多数据结构的题,但是数据结构考试还是头一回,在考试里快速想到最优算法还是挺不容易的,慢慢地一步一步来吧。