您的位置:首页 > 其它

PAT 1008. 数组元素循环右移问题

2016-04-28 21:41 302 查看
题目信息:

一个数组A中存有N(N>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向右移M(M>=0)个位置,即将A中的数据由(A0 A1……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

分析:题目只是说明了M>=0,那么有可能M>=N。当超过整个数组的长度,实际只要向右循环M-N位就可以了。所以,首先要对循环的位数和数组长度取余数,即move=M%N。要求尽量少的移动,如果使用最直接的方法,每次循环右移动M位,需要移动M*N次。其实仔细想想有规律。一个长度为6的数组为1 2 3 4 5 6,向右移动两位,先从元素1开始,元素1要移动到元素3的位置,元素3到了元素5的位置,元素5回到起始的元素1的位置。再由元素2开始,元素2到了元素4的位置,元素4到了元素6的位置,元素6到了起始的元素2的位置。a[i+2]=a[i],当i+2超过数组长度时,对数组长度进行取余数就可以了,当i+2的位置到了起始位置,本次移动结束了。如图。



但是该如何控制数组起点呢?长度为6的话有两个起始位置,如果数组为1 2 3 4 5 6 7向右移动两位 1->3->5->7->2->4->6->1;起始位置只有一个。仔细观察发现从一次起点开始,遍历过最小的位置就是以后循环的边界,如长度为6,第一右移动为1->3->5->1最小的数为3。位置3就是边界。第二次移动的位置就是上一次加一,即位置2,小于位置3。所以还要从位置2再次进行右移。而长度为7,移动的最小位置为2,所以起始位置只有一个。

用这种方法数组长度为多少位,就移动多少位。时间复杂度O(n),比最直接的方法高效。

C语言实现:

//24K丶小烦
#include<stdio.h>
#define LENGTH 100

int main()
{
int count=0,move=0,i=0,looper=101,data[LENGTH];
int param=0,save=0,temp=0,j=0;
scanf("%d%d",&count,&move);
move%=count;  //处理移动
for(i=0;i<count;i++)
scanf("%d",&data[i]);
if(move)   //移动0位不移动数组
{
for(j=0;j<looper;j++)
{
param=j+move,save=data[j],temp; //记录起始位置
while(param!=j)   //回到起始位置
{
if(save!=data[param])  //相同元素不移动
{
temp=data[param];
data[param]=save;
save=temp;
}
if(param>j&&looper>param)
looper=param;  //超过数组长度
param=(param+move)%count;
}
data[j]=save;     //回到当前位置
}
}
for(i=0;i<count;i++)
{
printf("%d",data[i]);
if(i!=count-1)
printf(" ");
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: