题目:移动元素
(13 分)设将 n(n>1)个整数存放到一维数组 R 中。试设计一个在时间和空间两方面都尽可能高效的算
法。将 R 中保存的序列循环左移 p(0<p<n)个位置,即将 R 中的数据由( X0, X1…Xn-1)变换为(Xp,
Xp+1 …Xn-1, X0, X1…Xp -1)。要求:
⑴ 给出算法的基本设计思想。
⑵ 根据设计思想,采用 C 或 C++或 JAVA 语言描述算法,关键之处给出注释。
⑶ 说明你所设计算法的时间复杂度和空间复杂度。
前言:对于题目中未确定数据范围的变量如n,p如何在程序中表现?个人理解是封装成函数,并未将主函数截进来。如果固定变量的值的话,打好注释说明应该也是可以的,毕竟是从特殊到一般。写一个完整的程序肯定是正确的,但耗时耗力,所以实际可能要取一下巧。
思路一:开空间
思考:首先从暴力思路思考(简单省时),再重新开一个n空间的数组,将位置依次放入。移动的计算方式为(i-p+n)%n,简单的求余公式,有循环放置的效果。
void remove1(int R[],int p,int n)
{
for(int i=0;i<n;i++)
{
b[(i-p+n)%n]=R[i];
}
for(int i=0;i<n;i++)
{
R[i]=b[i];
}
}
时间复杂度:O(n),空间复杂度:O(n)
思路二:不开空间(思路错误)
思考:能不能不开空间,直接通过思路的移动公式换位置呢?实践后发现不行,要用的数据会被移动的早的覆盖掉。
思路三:倒置(最优解)
思考:移动p个位置,理解将p个元素左移,n-p个元素也要跟着移动,变化的样子如图下。方法为两部分先内部倒置一下,然后两块再倒置一下。实现的效果即为题目要求的。具体证明或涉及到的理论部分建议查阅王道冲刺课真题讲解。第三步放第一步一样的效果。
void remove3(int R[],int l,int r)
{
int tmp;
for(int i=l,j=r;i<=j;i++,j--)//双指针交换
{
tmp=R[i];
R[i]=R[j];
R[j]=tmp;
}
}
//用双指针交换这种思路从0或从1开始都一样
remove3(a,1,p);
remove3(a,p+1,n);
remove3(a,1,n);
时间复杂度:O(n),空间复杂度:O(1)
参考博客:繁星蓝雨