1. 程式人生 > >陣列迴圈移位的幾種解法

陣列迴圈移位的幾種解法

題目描述:
設計一個演算法,把一個含有N個元素的陣列迴圈右移K位。

解法一:
最容易想到的就是每次將陣列中的元素右移一位,迴圈K次。

#include<iostream>
using namespace std;
void RightShift(int *arr, int N, int K){
     while(K--){
          int t = arr[N-1];
          for(int i = N-1;i>0;i--){
                arr[i]=arr[i-1];
          }
          arr[0
]=t; } } int main(){ int num[4] = {1,3,7,9}; for(int i = 0; i < 4;i++){ cout<<num[i]<<' '; } cout<<'\n'; RightShift(num,4,2); for(int i = 0; i < 4;i++){ cout<<num[i]<<' '; }

這裡的複雜度為K*N次,我們接下來再用一個方法來改進。

解法二:
用空間來換時間,申請一個大小為K%N的陣列,因為迴圈移位K次,如果K > N,則其效果與移動K%N次是一樣的。所以在解法一,我們可以加上 K = K %N 這句。
假如原陣列: 1 2 3 4 5 6 7 需要右移4次,那麼我們想要的結果是: 5 6 7 1 2 3 4
我們注意到,其實就是將1234前四個元素拿出來(變成array A: _ _ _ _ 5 6 7, array B:1 2 3 4),然後將567前移充填(A 變成 5 6 7 _ _ _ _),然後我們只要將 B 陣列再新增到A 陣列後面就完成了。 最後 (A : 5 6 7 1 2 3 4)

void RightShift(int *arr, int N, int K){
     K = K % N;
     int *sp = (int*)malloc(K*sizeof(int));
     int i = 0,s = 0;
     for(; i < K;i++){        // 將陣列前K 位存入sp中
         sp[i] = arr[i];
     }
     for(;i<N;i++,s++){       // 將陣列第K+1 - N 位移到arr前端。
        arr[s] = arr[i];
     }
     for(i = 0
; s < N;i++,s++){ // 將sp中的數取出,拼入arr陣列。 arr[s] = sp[i]; } }

這裡對陣列進行了複製K次,將後面的元素前移N-K次,然後再將K 個元素拼接到陣列後面進行了K次操作,一共進行了N+K次操作。然而空間複雜度為K.

解法三:
這裡有一個很巧妙的方法來實現陣列迴圈。
假如原陣列: 1 2 3 4 5 6 7 需要右移4次,那麼我們想要的結果是: 5 6 7 1 2 3 4。
1.將1234逆置 變成 4321
2.將567逆置 變成 765
3.將兩個逆置陣列拼接: 4321765
4.將這個已拼接的陣列逆置: 5671234 就成了我們想要的結果了。

void Reverse(int *arr,int start,int end){      //逆置
    for(; start < end;start++,end--){
           int s = arr[end];
           arr[end] = arr[start];
           arr[start] = s;
      }
}

void RightShift(int* arr,int N, int K){
      K = K%N;                       //對應上文步驟
      Reverse(arr,0,K-1);           //1 
      Reverse(arr,K,N-1);           //2
      Reverse(arr,0,N-1);           //4
}

上述演算法Reverse函式時間複雜度分別為K/2, (N-K)/2,N/2, 所以總的複雜度為O(N),空間複雜度為O(1)