演算法設計與分析學習筆記——最長公共子序列
最長公共子問題
待解決問題:
給定兩個序列X和Y,求其一個最長公共的序列Z。
補充解釋:X(m)={x1, x2,,,,,xm},Y(n)={y1, y2,,,,,yn},X和Y可以有共同的元素,Z是這些共同元素的集合,其元素順序在XYZ中都是升序排序的(Z中元素的順序不能在X,Y中出現前後顛倒的情況)。
例子:X={A,B,C,B, D,A, B},Y={B, D,C, A,B,A},那麼序列{B, C, B, A}是X和Y的最長公共子序列。{B, C, A}也是X和Y的子序列,但它不是最長的。
窮舉法
最常見的方法就是窮舉法,它的思路是:分別列舉出X和Y的所有序列,接著比較X和Y的所有子序列,選擇公共序列,最後選擇長度最長的公共序列,這個公共序列就是我們要求的最長公共子序列。
子結構分析:
我們發現,如果X和Y的長度都很短(假設長度都為1),我們很容易得出最優解,但是事實往往是很殘酷的。如果給定一組長度很長的X,Y,我們利用分治策略的思路,能不能從X和Y的子段中一步一步得出答案呢?
分治策略和動態規劃第一步都需要刻畫最優解的結構。下面先來看一下最長公共子序列最優解的結構。
假設X(m) = {x1, x2.....xm} 和 Y(n) = {y1, y2....yn}的最長公共子序列為Z = {z1, z2....zk},現在考慮一下X(m-1)和Y(n-1)的最優解和Z之間的關係。
1.如果X和Y的最後一個元素相等,並且等於Z的最後一個元素,那麼說明Z(k-1)是X(m-1)和Y(n-1)的公共子序列
2.如果xm != yn,並且xm和yn也不等於zk,那麼,Z是X(m-1)和Y(n-1)的公共子序列
3.如果xm != yn,zk = xm != yn,那麼Z是X(m)Y(n-1)的最長公共子序列
4.如果xm != yn,zk = yn != xm,那麼Z是X(m-1)Y(n)的最長公共子序列
在分析了X(m),Y(n)的解的結構之後,再於x(m-1),y(n-1)的解結構作對比,我們可以發現:Z被分類到以上三種情況的哪一種,主要取決於X,Y的最後一個元素是否相等,所以我們可以歸納出一個遞迴函式:
定義:c[i][j]為X(i)和Y(j)的最長公共序列(i <= m, j <= n)
判斷退出遞迴條件:如果 i 和 j 有一個等於0,可以立即得出並返回結果:當前兩個子序列的最長公共子序列長度為0。
比對當前X,Y的最後一個元素。
如果Xi = Yj,那麼返回結果:c[i][j] = c[i -1 ][j - 1] + 1
如果Xi != Yj,那麼返回結果:max{ c[i][j - 1], c[i - 1][j] }
在這個遞迴函式裡,我們每次在求c[i][j]的時候,需要使用c[i-1][j-1]等形式的值,我們一開始是不知道的。例如現在我們要求c[5][4],我在這層函式裡發現需要使用c[4][4]的值,我現在不知道,怎麼辦呢?我們只需要建立一個同樣的函式,並且把(4, 4)這兩個引數送給它就行了,同樣,這個新函式也可能不會直接知道c[4][3]的值,這個新函式可以再建立個同樣的函式,把(4, 3)送進去就行了....直到再建立的函式遇到了退出遞迴的條件,並且向上返回了0這個值。上一層函式拿到這個0值做一次處理之後再向上返回到上一層函式....
動態規劃
程式碼如下
求解例題c[7][6,]矩陣構造方法及過程
1.把序列分別按橫向和豎向填入矩陣的第一行和第一列
2.比對第一行和第一列單元格所對應的兩個字母(黃色區域),字母不同填入前面(或者上面)的數字,字母相同則填入(前面的數字+1),但不得超過這個單元格的行數和列數最小的那一個。
3.依次按行或按列填入數字。如果單元格對應的字母不同,填入這個單元格正上方和正前方最大的那一個;如果字母相同,填入(這個單元格正上方和正前方最大的數+1),但不得超過行數和列數最小值。
橫向Y,豎向X | B | D | C | A | B | A |
A | 0 | 0 | 0 | 1 | 1 | 1 |
B | 1 | 1=MAX(0,1)+0 | 1=MAX(0,1)+0 | 1=MAX(1,1)+0 | 2=MAX(1,1)+1 | 2=MAX(1,2)+0 |
C | 1 | 1=MAX(1,1)+0 | 2=MAX(1,1)+1 | 2=MAX(1,2)+0 | 2=MAX(2,2)+0 | 2=MAX(2,2)+0 |
B | 1 | 1=MAX(1,1)+0 | 2=MAX(2,1)+0 | 2=MAX(2,2)+0 | 3=MAX(2,2)+1 | 3=MAX(2,3)+0 |
D | 1 | 2=MAX(1,1)+1 | 2=MAX(2,2)+0 | 2=MAX(2,2)+0 | 3=MAX(3,2)+0 | 3=MAX(3,3)+0 |
A | 1 | 2=MAX(2,1)+0 | 2=MAX(2,2)+0 | 3=MAX(2,2)+1 | 3=MAX(3,3)+0 | 4=MAX(3,3)+1 |
B | 1 | 2=MAX(2,1)+0 | 2=MAX(2,2)+0 | 3=MAX(3,2)+0 | 4=MAX(3,3)+1 | 4=MAX(4,4)+0 |
從矩陣右下角開始往左上角尋找+1的記錄,例題矩陣中被塗成了紅色。每尋找到一個+1的單元格,記錄對應的字母並且刪除該單元格右方和下方所有的單元格。此題有兩個解,分別是{B,C,A,B}和{B,C, B, A}