1. 程式人生 > >斯坦福演算法設計和分析_3. 分治演算法

斯坦福演算法設計和分析_3. 分治演算法

​本文預計閱讀時間4分鐘,在讀的過程中你需要帶著以下問題:
  • 分治演算法的基本步驟
  • 逆序對計數是如何使用分治演算法來解決問題的
  • 為什麼MergeSort排序法可以自然的算出逆序對數目
分值策略一般步驟
  1. 把輸入劃分成更小的子問題。
  2. 遞迴的治理子問題。
  3. 把子問題的解決方案組合到一起,形成原始問題的解決方案。
應用: 逆序對數目 輸入包含不同整數的陣列A, 輸出A中逆序對的數量,逆序是指: 如果 i < j 而 A[i] > A[j],那麼 (i, j) 就是一組逆序對。 比如輸入的陣列是 其中i = 2對應A[2] =3 ,j=4對應A[4]=2,2<4, 但是A[2] > A[4],所以這是一組逆序對。 協同篩選 為什麼要對陣列的逆序對計算? 一個原因是想要計算一種數值相似度,該數值的相似度用於對兩個已排序列表之間的相似度進行量化。比如兩個人都看過10部電影,按照從最喜歡到最不喜歡的順序進行排列,那麼怎麼衡量兩個人的選擇是相似還是不相似的呢?解決這個問題的一種量化方法就是通過包含10個元素的陣列A,A1表示讀者的朋友從電影列表中選擇最喜歡的電影,a2表示他喜歡第二的電影,以此類推,a10表示他最不喜歡的電影,這樣如果讀者最喜歡的電影是星球大戰,而這部電影在讀者的列表中只顯示的第5位,那麼a1就等於5,如果兩個人的排序是相同的,這個陣列就已經排序了,不存在逆序對,如果這個陣列包含的逆序對越多,讀者和朋友之間對電影評價的分歧就越多,對電影的偏好就不同了。 對已排序列表進行相似性測量的另一個原因就是協同篩選,這是一種任意生成推薦方案的方法,網站就怎麼推出關於產品電影歌曲內容的建議呢?在協同篩選中,其思路就是尋找其他與它相似偏好的使用者,然後推薦他們所喜歡的內容。因此協同篩選需要使用者“相似性”的定義,而計算逆序對就可以捕捉問題的本質。 暴力解法
我們首先想到的就是暴力窮舉搜尋法,輸入一個數組A,裡面包含不同的整數,輸出的是它的逆序對個數,以上就是暴力解法的虛擬碼。外層迴圈i表示從左到右的遍歷陣列A中的元素,內層迴圈j是沒有與i對比過的元素,逆序了就累加。它的缺點是時間複雜度很高,O(n^2)。 分而治之思想 如果我們用分治演算法來算這個問題的話,第一個步驟就是把陣列A劃分成更小的子問題,我們把A平均的劃分成兩個部分,左邊和右邊,這樣陣列規模就變小了,這樣劃分下就有三種情況:
  • 第1種就是逆序對 i 和 j 都位於陣列的左半部分,就是下標 i 和 j 是小於等於n/2的
  • 第2種情況是逆序對 i 和 j 位於陣列的右半部分
  • 第3種情況是逆序對 i 位於左半部分 j 位於右半部分,以上是虛擬碼。
接下來我們需要解決子問題,對於情況1,2其實就是呼叫自身的遞迴,所以我們只用實現第3鍾情況CountSplitInv。 MergeSort思想 在CountInv的虛擬碼中,需要實現CountSplitInv函式,我們之前講的MergeSort排序演算法天然的可以計算逆序對數目,而它實現的思路又是兩個已排序的數組合併成一個新陣列,上面的CountInv的情況3實際就是i在左邊陣列中,j在右邊陣列中,而左右兩邊的陣列沒有排序,所以我們對他兩排一下序就能引用MergeSort演算法。我們稍微的修改一下上面的虛擬碼,使得遞迴後除了返回逆序對數目,還要返回排序後的陣列,下面是修改後的虛擬碼。
那麼以上在處理逆序對 i, j 一個在左邊一個在右邊這種情況的時候,就可以用上之前的MergeSort演算法,現在我們來回顧一下。 以上是MergSort的虛擬碼,它是輸入已排序的C和D,輸出是排序好的B。i,j分別控制C,D的元素,哪個元素小就把它加入到B中。那麼,這裡的C就是原問題中的左半部,D就是原問題的右半部分,當C[i] > D[j] 的時候,說明產生了逆序對,而C又是排序後的,所以i之後的數字都是大於D[j]的,所以對於D[j]所帶來的逆序對數目就是C陣列i到最後的元素個數,所以,我們可以在排序的基礎上計算出逆序對個數。把這一段話翻譯成虛擬碼就是如下。 這樣就完成了分治演算法對於逆序對的計算。時間複雜度是O(nlogn),比暴力搜尋快很多。文章開頭的問題你想通了嗎?           &nbs