1. 程式人生 > >最長公共子串和最長公共子序列之Python實現

最長公共子串和最長公共子序列之Python實現

動態規劃(dynamic programming)是運籌學的一個分支,是求解決策過程(decision process)最優化的數學方法。簡單的理解為:是將一個棘手的問題,分成一個個小問題,先著手解決這些小問題,最後找到解決最優解的優化過程。動態規劃一般可分為線性動規,區域動規,樹形動規,揹包動規四類。在這裡,我們主要解決揹包動態規劃問題。用一個示例展開:

假如你要去野營。你有一個容量為6磅的揹包,需要決定該攜帶下面的哪些東西。其中每一樣東西都有相應的價值,價值越大意味著越重要:

  • 水(重3磅,價值10);
  • 書(重1磅,價值3);
  • 食物(重2磅,價值9);
  • 夾克(重2磅,價值5);
  • 相機(重1磅,價值6
    )。

請問攜帶哪些東西時價值最高?

對於這樣一個問題,我們去對這些東西相互組合,算出最高價值是可以的,但是,會很浪費時間,可能會到最後越來越糊塗。所以最好的方法是,使用動態規劃將問題分解為小問題,再求出最高價值。具體使用的方法是——網格法。

構建這個一個網格,將揹包分成1到6磅的空間,分別考慮有書;有書和相機;有書、相機和食物;有書、相機、食物和夾克;有書、相機、食物和夾克、還有水的情況下揹包容下東西的最大價值。

然後,我們就可以得到下面這個完整的網格:


這能說明什麼問題呢?或者說它是怎麼得來的呢?

這個表格是一個迭代的過程,隨著行和列的逐步增加,考慮價值如何最大。

從中舉一個例子:當揹包只有1磅容積的時候,只能放一本書,此時價值為3。當揹包有2磅容積的時候,有兩樣東西(書和相機),此時價值為9。當揹包有3磅容積的時候,此時如果有三樣東西(書、相機和食物),應該優化選擇相機和食物,而不是書和食物,因為,它們的價值更大些。

就按照這種規則優化取東西,最終當揹包為6磅時,選擇相機、食物和水是最大價值的。

這就是一個簡單運用動態規劃解決問題的範例。但是,值得注意的是:動態規劃功能強大,但是僅當分離出來的子問題都是離散的,即不依賴其他的子問題時,動態規劃才是管用的。

下面,將討論兩個運用動態規劃的例項:最長公共子串最長公共子序列

如果要識別兩個單詞之間的相識度,找出兩個單詞的最長公共子串和最長公共子序列也可以用到動態規劃。首先也是用網格的方式將兩個單詞表示出來。比如:比較hish和fish。

最長公共子串:表示的是兩個單詞中連續的相同字母長度。


然後,將表格填完整。具體怎麼填呢?這就要規定一個準則了。如下所示:


實現這個公式的虛擬碼類似於下面這樣:

# 兩個字母相同
if word_a[i] == word_b[j]:
    cell[i][j] = cell[i-1][j-1] + 1
# 兩個字母不同
else:
    cell[i][j] = 0
需要注意的一點是:對於最長公共子串問題,答案為網格中最大的數字——它可能並不位於最後的單元格中。

最長公共子序列:表示的是兩個單詞中相同的字母的長度。

比如:fosh,與fish相近還是與fort相近呢?

如果用最長公共子串的方法則是相同的,都有兩個字母連續相同。但是,這裡我們是不是應該一眼看出其實fish更相近一些呢,因為它有三個字母與fosh相同。

這裡,我們就該使用最長公共子序列的方法。

同樣,先構建網格。這個時候的規則應該如下:


用虛擬碼的形式表示:

# 兩個字母相同
if word_a[i] == word_b[j]:
    cell[i][j] = cell[i-1][j-1] + 1
# 兩個字母不同
else:
    cell[i][j] = max(cell[i-1][j], cell[i][j-1])
這樣就解決了。其實,這個最長公共子串和最長公共子序列方法主要來確定DNA鏈的相似性有很好的幫助。

作為一名初學者,歡迎您批評指正!謝謝大家。。。

注:

參考書:《演算法圖解》

完整程式碼演示:

http://download.csdn.net/download/llh_1178/10034807