一个数组A中存有N(N>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(M>=0)个位置,即将A中的数据由(A0A1……AN-1)变换为(AN-M …… AN-1 A0 A1……AN-M-1)(最后M个数循环移至最前面的M个位置)。如果需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?
输入格式:每个输入包含一个测试用例,第1行输入N ( 1<=N<=100)、M(M>=0);第2行输入N个整数,之间用空格分隔。
输出格式:在一行中输出循环右移M位以后的整数序列,之间用空格分隔,序列结尾不能有多余空格。
输入样例:6 2 1 2 3 4 5 6输出样例:
5 6 1 2 3 4
题目链接:http://www.patest.cn/contests/mooc-ds2015spring/00-%E8%87%AA%E6%B5%8B3
刚开始花了不少时间在想,用一种比较简单的方法解决,下面同时把几种网友的方法也做一下简单汇总。
下面是一种很简单易懂的方式,利用数组多余的空间进行替换。
方法一:扩大数组空间,根据相应规则将前N个数值重新组合 分析:时间: O(1);空间:O(2*n)。
<pre name="code" class="cpp"> void m::move_k1(int *a,int n,int k) { int i; //当M<=N-M时,先把最后M个数值放置在前M个,剩余的再重排 if(k<=n-k) { for(i=0;i<k;i++) a[i]=a[2*n-(k-i)]; for(i=k;i<n;i++) a[i]=a[n-k+i]; } //当M>N-M时,先把前面N-M个数值放置在后N-M个,剩余的再重排 else { for(i=k;i<n;i++) a[i]=a[i-k+n]; for(i=0;i<k;i++) a[i]=a[2*n-k+i]; } }
方法二:每次移动一个元素,移动k次。 分析:时间: O(n * k);空间:O(1)。
<pre name="code" class="cpp"> //向右循环移动
void m::move_k1(int *a,int n,int k)
{
int i;
for(i=0;i<k;i++) //向右移k次
{
int temp;
int j=-1;
temp=a[n-1];
for(j=n-1;j>0;j--) //每次向右移一位
a[j]=a[j-1];
a[0]=temp;
}
}
方法三:通过三次倒置运算,得到最终结果
分析:时间: O(n);空间:O(1)。
<pre name="code" class="cpp"> m1.reverse(a,0,n-1);//将所有元素逆置;
m1.reverse(a,0,k-1);//将前k个元素逆置;
m1.reverse(a,k,n-1);//将后 n-k个元素逆置;
void m::reverse(int *a,int p,int q)
{
int i;
· for(i=p;i<=(p+q)/2;i++)
{
int temp;
temp=a[i];
a[i]=a[p+q-i];
a[p+q-i]=temp;
}
}
还有通过最大公约数欧几里得算法求解的,有兴趣可以继续搜索。