一个数组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
思路:本题有两种做法(首先题目中并没有说m的大小,可能为0,也可能比n大,所以在题目开始的时候就要m=m%n修正m的值)
1.题目只要求输出最终的结果,并没有要求给定的数组一定改变,所以第一种方法就是直接把题目要求的输出
2.第二种方法就是将数组改变,将数组中n-m位置处的元素赋给中间变量,然后把前面的元素向后移动,一次类推,直到回到n-m位置处,接着循环n-m+1处。此处有一个问题
就是有可能经过一次循环之后数组就满足了题目要求了,比如n=8,m=3,从8-3=5的位置循环一边就好了,没有必要循环下标6的位置。这里就用到了n和m的最大公约数d,
循环是从n-m开始,直到n-m+d-1结束。所要循环的次数实际上是d次,假如nm的最大公约数是gcd(7,4)=1,那么就需要循环一次。
#include<iostream> using namespace std; int a[110]; int main() { int n,m; cin>>n>>m; for(int i=0;i<n;i++) { cin>>a[i]; } int tmp; m=m%n; //因为没有说n,m的大小,所以可能出现m比n大 的情况,此处修正m if(m==0) //m=0时,直接输出原数组 { for(int j=0;j<n;j++) { if(j<n-1)cout<<a[j]<<" "; else cout<<a[j]; } } else //m不等于0时,直接将要移动的数按顺序输出,不管平移后的数组是什么样的 { for(int k=m-1;k>=0;k--) { cout<<a[n-k-1]<<" "; } for(int h=0;h<n-m;h++) { if(h<n-m-1)cout<<a[h]<<" "; else cout<<a[h]; } } return 0; }
#include<iostream> using namespace std; int a[110]; int gcd(int a,int b) //最大公约数 { int c=1,tmp; while(c<=b) { if((a%c==0)&&(b%c==0))tmp=c; ++c; } return tmp; } int main() { int n,m; cin>>n>>m; for(int i=0;i<n;i++) { cin>>a[i]; } m=m%n; if(m!=0) { int tmp,tmp1,tmp2; tmp1=n-m; //循环开始的位置 tmp2=n-m+gcd(n,m); //循环结束的位置 int pos,next; for(int j=tmp1;j<tmp2;j++) { tmp=a[j]; //将循环开始的位置元素赋给中间变量tmp pos=j; //将循环开始的位置赋给pos do { next=(pos-m+n)%n; if(next!=j)a[pos]=a[next]; //如果没有循环到挑出去的元素,就把前面的元素赋给后面 else a[pos]=tmp; //如果循环到了挑出去的那个元素,说明一遍循环完毕,将挑出去的元素赋给pos pos=next; //将前面元素的位置赋给当前位置 }while(pos!=j); //循环到pos位置和挑出去元素位置重合的时候停止循环 } } for(int i=0;i<n;i++) //输出数组中的元素 { if(i<n-1)cout<<a[i]<<" "; //此处for循环是将m=0和m!=0的情况一同输出的 else cout<<a[i]; } return 0; }