首先使用的是暴力输出法:
1 #include<iostream> 2 3 using namespace std; 4 5 int main(){ 6 int N,M; 7 cin>>N>>M; 8 9 int a[N]; 10 for(int i=0;i<N;i++) 11 cin>>a[i]; 12 13 M=M%N; 14 if(M==0) 15 { 16 cout<<a[0]; 17 for(int i=1;i<N;i++) 18 cout<<" "<<a[i]; 19 } 20 else 21 { 22 cout<<a[N-M]; 23 for(int i=N-M+1;i<N;i++) 24 cout<<" "<<a[i]; 25 26 for(int i=0;i<N-M;i++) 27 cout<<" "<<a[i]; 28 } 29 return 0; 30 }
搜索一下发现一种神奇的解法:三次逆置法
设计一个算法,把一个含有N个元素的数组循环右移K位,要求时间复杂度为O(N),且只允许使用两个附加变量。
我们还是把字符串看成有两段组成的,记为XY。左旋转相当于要把字符串XY变成YX。
我们先在字符串上定义一种翻转的操作,就是翻转字符串中字符的先后顺序。把X翻转后记为XT。显然有(XT)T=X。 我们首先对X和Y两段分别进行翻转操作,这样就能得到XTYT。接着再对XTYT进行翻转操作,得到(XTYT)T=(YT)T(XT)T=YX。正好是我们期待的结果。 分析到这里我们再回到原来的题目。我们要做的仅仅是把字符串分成两段,第一段为前面m个字符,其余的字符分到第二段。
再定义一个翻转字符串的函数,按照前面的步骤翻转三次就行了。时间复杂度和空间复杂度都合乎要求。 假设原数组序列为abcd1234,要求变换成的数组序列为1234abcd,即循环右移了4位。
比较之后,不难看出,其中有两段的顺序是不变的:1234和abcd,可把这两段看成两个整体,右移K位的过程就是把数组的两部分交换一下,
变换的过程通过一下步骤完成: 1、逆序排列abcd:abcd1234--->dcba1234; 2、逆序排列1234:dcba1234--->dcba4321; 3、全部逆序:dcba4321--->1234abcd。
Reverse(int *arr, int b, int e) //逆序排列 { for( ; b < e; b++, e--) //从数组的前、后一起遍历 { int temp = arr[e]; arr[e] = arr[b]; arr[b] = temp; } } RightShift(int *arr, int N, int K) { K = K % N ; Reverse(arr, 0, N-K-1); //前面N-K部分逆序 Reverse(arr, N-K, N-1); //后面K部分逆序 Reverse(arr, 0, N-1); //全部逆序 }
//原文链接:https://blog.csdn.net/hackbuteer1/article/details/6699837
注:在<algorithm>中有相同作用的函数函数:reverse :将范围内元素重新按反序排列。
1 #include<iostream> 2 #include<algorithm> 3 4 using namespace std; 5 6 int main(){ 7 int N,M; 8 cin>>N>>M; 9 10 int *p=new int[N]; 11 for(int i=0;i<N;i++) 12 cin>>p[i]; 13 14 M=M%N; 15 16 reverse(p,p+N-M); 17 reverse(p+N-M,p+N); 18 reverse(p,p+N); 19 20 cout<<p[0]; 21 for(int i=1;i<N;i++) 22 cout<<" "<<p[i]; 23 24 delete[] p; 25 26 return 0; 27 }