最長公共子序列(LCS)


觀看了麻省理工大學的算法導論課程,講解了動態規划求解最長公共子序列的方法,受益匪淺,現做個總結。
 
1、公共子序列和公共子串的區別
公共子串是指連續的公有字符串,公共子序列是指兩個字符串都任意刪除0個或多個字符后得到的公有字符串,子序列可以是不連續的。
舉個例子吧,有兩個字符串,串A為“1 2 3 4 5 6 7”,串B 為“1 3 4 5 8 7”,很明顯,A和B的公共子串為“3 4 5”,A和B的公共子序列可以是 “3 5”,或是“1 3 7”,等等。
 
最長公共子串:在兩個字符串中找到一個最長的公共子串,要求子串在原串中是連續的。
最長公共子序列:在兩個字符串中找到一個最長的公共子串,不要求子串在原串中是連續的。
2、問題描述
現有兩個序列x[1...m],y[1...n],要求出兩個序列的最長公共子序列。
假設x和y如下:
x[1...m] = {A, B, C, B, D, A, B};
y[1...n] = {B, D, C, A, B, A};
3、窮舉法
  • 求出x中所有包含的子序列數:2^m
  • 檢測y中是否包含每一個子序列:n
時間復雜度為:O(2^m * n),消耗天價的時間,明顯不合格。
4、動態規划求解
先假設有 C[i,j] = | LCS(x[1...i] , y(1...j)) |,則有:
  根據上面要求可以寫出求解LCS問題的偽代碼:
 
1  LCS(x,y,i,j)  
2      if x[i] = y[j]  
3          then C[i,j] ← LCS(x,y,i-1,j-1)+1  
4      else C[i,j] ← max{LCS(x,y,i-1,j),LCS(x,y,i,j-1)}  
5    return C[i,j]

  為了在求解過程中不進行重復計算,用一個二維數組來暫時存儲已經計算過的值,犧牲空間來獲得時間上的優化。

  代碼如下:
 1 public class LCS {
 2     public static int[][] vals ;
 3 
 4     public static int getLCS(String str1,String str2){
 5         int len1 = str1.length();
 6         int len2 = str2.length();
 7 
 8         vals = new int[len1+1][len2+1];
 9 
10         for(int i=0;i<len1;i++){
11             // 二維數組從[1][1]開始進行有效存儲
12             int fi = i+1;
13             for(int j=0;j<len2;j++){
14                 int fj = j+1;
15                 //字符相同
16                 if(str1.charAt(i) == str2.charAt(j)){
17                     // 滿足第一種狀況
18                     vals[fi][fj] = vals[fi-1][fj-1] + 1;
19                     //字符不相同
20                 }else if(str1.charAt(i) != str2.charAt(j)){
21                     //滿足第二種狀況
22                     vals[fi][fj] = Math.max(vals[fi-1][fj],vals[fi][fj-1]);
23                 }
24             }
25         }
26 
27         for(int i=0;i<len1;i++){
28             System.out.println(Arrays.toString(vals[i]));
29         }
30 
31         return vals[len1][len2];
32     }
34     public static void main(String[] args) {
36         String str1 = "ABCBDAB";
37         String str2 = "BDCABA";
38         System.out.println(getLCS(str1,str2));
41     }
42 }

 輸出結果:

[0, 0, 0, 0, 0, 0, 0]
[0, 0, 0, 0, 1, 1, 1]
[0, 1, 1, 1, 1, 2, 2]
[0, 1, 1, 2, 2, 2, 2]
[0, 1, 1, 2, 2, 3, 3]
[0, 1, 2, 2, 2, 3, 3]
[0, 1, 2, 2, 3, 3, 4]
4

 


免責聲明!

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



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