數組循環右移

設計一個算法,把一個含有N個元素的數組循環右移K位,要求時間複雜度爲ON),且只容許使用兩個附加變量。算法

不合題意的解法以下:編程

咱們先試驗簡單的辦法,能夠每次將數組中的元素右移一位,循環K次。abcd1234→4abcd123→34abcd12→234abcd1→1234abcd。僞代碼以下:數組

代碼清單2-33設計

 

 

RightShift(int* arr, int N, int K)變量

{循環

    while(K--)算法複雜度

    {時間

        int t = arr[N - 1];思考

        for(int i = N - 1; i > 0; i --)while

            arr[i] = arr[i - 1];

        arr[0] = t;

    }

}

雖然這個算法能夠實現數組的循環右移,可是算法複雜度爲ON),不符合題目的要求,須要繼續往下探索。

 

分析與解法

假如數組爲abcd1234,循環右移4位的話,咱們但願到達的狀態是1234abcd。不妨設K是一個非負的整數,當K爲負整數的時候,右移K位,至關於左移(-K)位。左移和右移在本質上是同樣的。

【解法一】

你們開始可能會有這樣的潛在假設,K<N。事實上,不少時候也的確是這樣的。但嚴格地說,咱們不能用這樣的「慣性思惟」來思考問題。尤爲在編程的時候,全面地考慮問題是很重要的,K多是一個遠大於N的整數,在這個時候,上面的解法是須要改進的。

仔細觀察循環右移的特色,不難發現:每一個元素右移N位後都會回到本身的位置上。所以,若是K > N,右移K-N以後的數組序列跟右移K位的結果是同樣的。進而可得出一條通用的規律:右移K位以後的情形,跟右移K’= K % N位以後的情形同樣。

代碼清單2-34

RightShift(int* arr, int N, int K)

{

    K %= N;

    while(K--)

    {

        int t = arr[N - 1];

        for(int i = N - 1; i > 0; i --)

            arr[i] = arr[i - 1];

        arr[0] = t;

    }

}

可見,增長考慮循環右移的特色以後,算法複雜度降爲ON),這跟K無關,與題目的要求又接近了一步。但時間複雜度還不夠低,接下來讓咱們繼續挖掘循環右移先後,數組之間的關聯。

【解法二】

假設原數組序列爲abcd1234,要求變換成的數組序列爲1234abcd,即循環右移了4位。比較以後,不難看出,其中有兩段的順序是不變的:1234和abcd,可把這兩段當作兩個總體。右移K位的過程就是把數組的兩部分交換一下。變換的過程經過如下步驟完成:

1.   逆序排列abcdabcd1234 → dcba1234;

2.   逆序排列1234:dcba1234 → dcba4321;

3.   所有逆序:dcba4321 → 1234abcd

僞代碼能夠參考以下:

代碼清單2-35

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 %= N;

    Reverse(arr, 0, N – K - 1);

    Reverse(arr, N - K, N - 1);

    Reverse(arr, 0, N - 1);

}

這樣,咱們就能夠在線性時間內實現右移操做了。

相關文章
相關標籤/搜索