程序员面试100题之十一:数组循环移位
???? 不合題意的解法如下:
???? 我們先試驗(yàn)簡(jiǎn)單的辦法,可以每次將數(shù)組中的元素右移一位,循環(huán)K次。abcd1234--->4abcd123--->34abcd12--->234abcd1--->1234abcd。代碼如下所示:
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;} }?????? 雖然這個(gè)算法可以實(shí)現(xiàn)數(shù)組的循環(huán)右移,但是算法復(fù)雜度為O(K*N),不符合題目的要求,要繼續(xù)探索。
?????? 分析與解法
????? 假如數(shù)組為abcd1234,循環(huán)右移4位的話,我們希望達(dá)到的狀態(tài)是1234abcd。不妨設(shè)K是一個(gè)非負(fù)的整數(shù),當(dāng)K為負(fù)整數(shù)的時(shí)候,右移K位,相當(dāng)于左移(-K)位,左移和右移在本質(zhì)上是一樣的。
????? 解法一
???大家開(kāi)始可能會(huì)有這樣的潛在假設(shè),K<N。事實(shí)上,很多時(shí)候也的確是這樣的。但嚴(yán)格來(lái)說(shuō),我們不能用這樣的“慣性思維”來(lái)思考問(wèn)題。尤其在編程的時(shí)候,全面地考慮問(wèn)題是很重要的,K可能是一個(gè)遠(yuǎn)大于N的整數(shù),在這個(gè)時(shí)候,上面的解法是需要改進(jìn)的。
仔細(xì)觀察循環(huán)右移的特點(diǎn),不難發(fā)現(xiàn):每個(gè)元素右移N位后都會(huì)回到自己的位置上。因此,如果K>N,右移K-N以后的數(shù)組序列跟右移K位的結(jié)果是一樣的。進(jìn)而可得出一條通用的規(guī)律:右移K位之后的情形,跟右移K’=K%N位之后的情形一樣,代碼如下所示:
RightShift(int *arr, int N, int K) {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;} }???? 可見(jiàn),增加考慮循環(huán)右移的特點(diǎn)之后,算法復(fù)雜度降為O(N^2),這跟K無(wú)關(guān),與題目的要求又接近了一步。但時(shí)間復(fù)雜度還不夠低,接下來(lái)讓我們繼續(xù)挖掘循環(huán)右移前后,數(shù)組之間的關(guān)聯(lián)。
??? 解法二
????? 我們還是把字符串看成有兩段組成的,記位XY。左旋轉(zhuǎn)相當(dāng)于要把字符串XY變成YX。我們先在字符串上定義一種翻轉(zhuǎn)的操作,就是翻轉(zhuǎn)字符串中字符的先后順序。把X翻轉(zhuǎn)后記為XT。顯然有(XT)T=X。
????? 我們首先對(duì)X和Y兩段分別進(jìn)行翻轉(zhuǎn)操作,這樣就能得到XTYT。接著再對(duì)XTYT進(jìn)行翻轉(zhuǎn)操作,得到(XTYT)T=(YT)T(XT)T=YX。正好是我們期待的結(jié)果。
????? 分析到這里我們?cè)倩氐皆瓉?lái)的題目。我們要做的僅僅是把字符串分成兩段,第一段為前面m個(gè)字符,其余的字符分到第二段。再定義一個(gè)翻轉(zhuǎn)字符串的函數(shù),按照前面的步驟翻轉(zhuǎn)三次就行了。時(shí)間復(fù)雜度和空間復(fù)雜度都合乎要求。
假設(shè)原數(shù)組序列為abcd1234,要求變換成的數(shù)組序列為1234abcd,即循環(huán)右移了4位。比較之后,不難看出,其中有兩段的順序是不變的:1234和abcd,可把這兩段看成兩個(gè)整體,右移K位的過(guò)程就是把數(shù)組的兩部分交換一下,變換的過(guò)程通過(guò)一下步驟完成:
1、逆序排列abcd:abcd1234--->dcba1234;
2、逆序排列1234:dcba1234--->dcba4321;
3、全部逆序:dcba4321--->1234abcd。
代碼如下所示:
Reverse(int *arr, int b, int e) //逆序排列 {for( ; b < e; b++, e--) //從數(shù)組的前、后一起遍歷{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); //全部逆序 }這樣,我們就可以在線性時(shí)間內(nèi)實(shí)現(xiàn)右移操作了。
總結(jié)
以上是生活随笔為你收集整理的程序员面试100题之十一:数组循环移位的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 程序员面试100题之十:快速寻找满足条件
- 下一篇: 程序员面试100题之十二:求数组中最长递