數組循環移位中的學問


  始終相信能聽明白和能說明白是兩種不同的境界,如果對於一件問題,你說你明白了,但是你卻不能說明白,那在我眼里就會有這樣的一個事實,那就是:你並沒有真正地明白。當然,也存在這種情況,那就是說是說明白了,但是未必對,這正是我擔心的情況,所以還請閱讀過我所有文章的朋友們指出我文章中的錯誤。謝謝你們……

1.問題定義

  設計一個算法,把一個含有n個元素的數組A循環右移k位,要求時間復雜度是O(n)的。舉個例子說明一下算法要達到的效果:數組中包含的元素為123456,現在要循環右移2位,則變成了561234 。

2.解決方案

2.1 朴素的思路

  往往是這樣,朴素的思路雖不能滿足題目的要求,但是確可能是優化的依據。對於這個問題朴素的解法是,每次完成一次右移,並且完成一次右移的時間復雜度是O(n),這樣的操作要進行k次,所以時間復雜度是O(n*k)。但是現在想一想,既然已經知道要右移的位數k,那么要是還一步一步的移是不是顯得有點笨了呢。為什么不一步到位呢?

2.2 空間換時間

  對於算法上的優化,以空間換時間是一種比較常規的辦法了。可以借助一個輔助數組T,先把數組A的n-k+1到n位數組中的元素存儲到T中,然后再把數組A中的1到n-k位數組元素存儲到輔助數組T中,然后將數組T中的元素復制回數組A,這樣就完成了數組的循環右移,時間復雜度為O(n),但是呢,卻增加了O(n)的空間復雜度。如果要求最多只能允許使用兩個輔助空間呢?這可就要想一想能不能進一步優化了。

2.3 利用“翻轉”完成優化

  考慮一下數組A中元素123456循環右移2位到底是怎么個情況!!!可不可以這樣實現呢?將數組A分成兩個部分:A[0~n-k-1] 和 A[n-k~n-1] ,將這兩個部分分別翻轉,然后放在一起在翻轉(逆序)。具體是這樣的:

(1)翻轉1234:123456 ---> 432156

(2)翻轉56:     432156 ---> 432165

(3)翻轉432165:432165 ---> 561234

看看吧,確實完成了翻轉的操作。現在來看一下代碼(灰常簡單):

 1 //逆序
 2 void Reverse(int A[],int b,int e)
 3 {
 4     for(;b < e;b++,e--)
 5     {
 6         int temp = A[b];
 7         A[b] = A[e];
 8         A[e] = temp;
 9     }
10 }
11 //循環右移
12 void RightShift(int A[],int,int n,int k)
13 {
14     Reverse(A,0,n-k-1);
15     Reverse(A,n-k,n-1);
16     Reverse(A,0,n-1);
17 }

現在可以分析一下時空復雜度了,時間復雜度顯然是O(n),主要是完成翻轉(逆序)操作,並且只用了一個輔助空間。顯然這是一個不錯算法哦。。。

注:

細心的讀者可能就發現,這里的右移並沒有說小於n呀,那么一個k>n那就會出現問題,經過簡單的分析,我們發現如果A[]={1,2,3,4,5,6},數組長度是6,那么循環右移7位和循環右移1位是一樣的,所以只需要把函數RightShift()中的k取值為k=k%n。如此一來問題就解決了。

學習中的一點總結,歡迎拍磚哦^^

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM