動態規劃的入門理解&例子(LIS、最小編輯距離)

關於動態規劃的講解有很多材料,這裏只是按照我自己的理解來表述動態規劃。可能並不詳細,也不一定完全準確。這裏主要通過兩個例子LIS和最小編輯距離進一步加深對於動態規劃的直觀理解。

1. 動態規劃入門理解

  • 動態規劃方法是把問題向前分解,想要解決一個問題,需要先解決這個問題的子問題,那麼要解決子問題,又需要解決子問題的子問題。通過先解決最小的子問題,再不斷的解決更上一層的問題,那麼就可以解決最終的問題。

  • 欲用動態規劃解決問題,首先需要對問題進行定義,利用數學語言描述問題。然後再對問題進行求解,求解的過程中是先求解小問題,再利用小問題的解去求解大問題。這是動態規劃中常用的流程。

  • 對問題的定義和求解小問題再求解大問題,其實就是定義狀態和解決狀態轉移。下面就用兩個例子(LIS和最小編輯距離)來解釋如何定義問題的狀態以及推導狀態轉移公式。

2. LIS(最長遞增子序列)

  • LIS問題是求一個長序列的子序列,使的這個子序列是遞增的,且是所有遞增的子序列中最長的。比如對於序列2 5 4 9 10 6 7 8 11,最長遞增子序列有兩個,2 5 6 7 8 11和 2 4 6 7 8 11。最長遞增子序列問題有時候是隻需要知道長度即可,對於前面的序列,最長遞增子序列的長度是唯一的,即=6。

  • 當然LIS問題是可以用動態規劃的思想來解決的。那麼首先思考如何定義問題的狀態。最容易想到的定義如下:

dk : 表示序列前k項的最長子序列

  • 對於這個定義,很明顯,子問題就是dk1 ,dk2 等,分別表示前k1 和前 k2 項的最長子序列。對問題進行定義後,是否合適呢?能否通過該定義推導出狀態轉移呢?如果對於每一項都求最長的子序列,並且狀態轉移使用ak 項和其它的最長子序列相比較的方式,選擇是否把ak 項加入。

  • 對於序列2 5 4 9 10 6 7 8 11

第一項:2
第二項:2 5
第三項:2 5
第四項:2 5 9
第五項:2 5 9 10
第六項:2 5 9 10
第七項:2 5 9 10
….

從這裏就可以看出來,該種狀態的定義和狀態轉移的定義是有問題的。6 7 8 這幾項不能發揮作用了。

  • 因此這裏選擇另外一種定義:

dk : 表示以第k項結尾的最長子序列

  • 那麼求出所有以1,2,3,4,5…,N項結尾的最長子序列後,選擇最長的作爲輸出即可。那麼對於這種狀態的定義,狀態的轉移是什麼樣子的呢?

hi={[di,ak],ifak>aiak,other

dk=hargmaxilen(hi)

也就是,求解序列[a1 , a2 , a3 , …, ak ]的最長遞增子序列,可以通過[a1 , a2 , a3 , … ak1 ]序列、[a1 , a2 , a3 , … ak2 ]、[a1 , a2 ]和[a1 ]的最長遞增子序列得到。要求長度爲k的序列的[a1 , a2 , a3 , …, ak ]最長遞增子序列,需要先求出序列[a1 , a2 , a3 , …, ak1 ]中以各元素(a1 ,a2 ,ak1 )作爲最大元素的最長遞增序列,然後把所有這些遞增序列與ak 比較,如果序列的末尾元素比ak 要小,則將元素ak 加入這個遞增子序列,如果序列末尾的元素比ak 大,則取ak ,那麼現在所有的序列都是以ak 結尾的,取出序列長度最長的作爲以第k項結尾的最長遞增子序列。(這裏可能會出現兩個序列長度一樣的情況,那麼可以隨機選一個,或者是選擇第一個)。

  • 對於前面的序列2 5 4 9 10 6 7 8 11,求解順序如下(存在兩個一樣長的序列時,選擇第一個):

第一項:2
第二項:2 5
第三項:2 4
第四項:2 5 9
第五項: 2 4 9 10
第六項:2 5 6
第七項:2 5 6 7
第八想:2 5 6 7 8
第九項:2 5 6 7 8 11

  • 另外,如果是求子序列,那麼是一邊計算,也是一邊需要保存各項的子序列的。如果是隻求子序列的長度,那麼只需要保存長度即可。

  • 採用這種方式求解最長遞增子序列,時間複雜度爲O(N2) ,還有更快的,時間複雜度爲O(NlogN) 的算法,這裏就不再解釋了。

3. 最小編輯距離

  • 最小編輯距離的問題,比較普遍,在平常的編碼過程中經常可能會遇到這個問題。最小編輯距離是指把字符串A轉換成字符串B所需要的最少操作數,這裏的操作包括刪除字、增加字、替換字三種操作。
  • 比如小明讓小紅告訴小剛:“今天天氣真好啊”,而小紅卻告訴小剛:“今天正好呀哈”。 那麼就可以用最小編輯距離表示這兩句話的區別。這裏,增加“天”字,增加“氣”字,修改“正”爲“真”,修改“呀”爲”啊”,刪除“哈”字。那麼最小編輯距離爲5。

  • 要用動態規劃的思想解決該問題,同樣需要考慮如何定義狀態和建立狀態轉移公式。

首先對問題進行定義:

di,j : 表示從句子A的前i個字轉移到句子B的前j個字的最小編輯距離

狀態轉移公式如下(假設句子A有N個字符,而句子B有M個字符):

di,j={j,if(i=0,j=0,1,2,3,...,M)i,if(j=0,i=0,1,2,3,...,N)max(di1,j+1,di,j1+1,di1,j1+issame)i=1,2,3,...,N,j=1,2,3,...,M

其中
issame={1,ifA[i]!=B[j]0,ifA[i]==B[j]

更詳細的最小編輯距離算法的說明,可以參考博客https://blog.csdn.net/qq_34552886/article/details/72556242

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章