(转)数组循环右移
設(shè)計一個算法,把一個含有N個元素的數(shù)組循環(huán)右移K位,要求時間復(fù)雜度為O(N),且只允許使用兩個附加變量。
不合題意的解法如下:
我們先試驗簡單的辦法,可以每次將數(shù)組中的元素右移一位,循環(huán)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 --)
????????????arr[i] = arr[i - 1];
????????arr[0] = t;
????}
}
雖然這個算法可以實現(xiàn)數(shù)組的循環(huán)右移,但是算法復(fù)雜度為O(K?*?N),不符合題目的要求,需要繼續(xù)往下探索。
?
分析與解法
假如數(shù)組為abcd1234,循環(huán)右移4位的話,我們希望到達(dá)的狀態(tài)是1234abcd。不妨設(shè)K是一個非負(fù)的整數(shù),當(dāng)K為負(fù)整數(shù)的時候,右移K位,相當(dāng)于左移(-K)位。左移和右移在本質(zhì)上是一樣的。
【解法一】
大家開始可能會有這樣的潛在假設(shè),K<N。事實上,很多時候也的確是這樣的。但嚴(yán)格地說,我們不能用這樣的“慣性思維”來思考問題。尤其在編程的時候,全面地考慮問題是很重要的,K可能是一個遠(yuǎn)大于N的整數(shù),在這個時候,上面的解法是需要改進(jìn)的。
仔細(xì)觀察循環(huán)右移的特點,不難發(fā)現(xiàn):每個元素右移N位后都會回到自己的位置上。因此,如果K?>?N,右移K-N之后的數(shù)組序列跟右移K位的結(jié)果是一樣的。進(jìn)而可得出一條通用的規(guī)律:右移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;
????}
}
可見,增加考慮循環(huán)右移的特點之后,算法復(fù)雜度降為O(N2),這跟K無關(guān),與題目的要求又接近了一步。但時間復(fù)雜度還不夠低,接下來讓我們繼續(xù)挖掘循環(huán)右移前后,數(shù)組之間的關(guān)聯(lián)。
【解法二】
假設(shè)原數(shù)組序列為abcd1234,要求變換成的數(shù)組序列為1234abcd,即循環(huán)右移了4位。比較之后,不難看出,其中有兩段的順序是不變的:1234和abcd,可把這兩段看成兩個整體。右移K位的過程就是把數(shù)組的兩部分交換一下。變換的過程通過以下步驟完成:
1.???逆序排列abcd:abcd1234 →?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);
}
這樣,我們就可以在線性時間內(nèi)實現(xiàn)右移操作了。
轉(zhuǎn)載于:https://www.cnblogs.com/boluo007/p/5470242.html
總結(jié)
- 上一篇: 1003 阶乘后面0的数量
- 下一篇: (五)Struts2 标签