PAT(Basic Level) 1008 陣列元素迴圈右移問題
阿新 • • 發佈:2020-07-23
首先使用的是暴力輸出法:
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 }