《算法導論》CLRS算法C++實現(十二)P208 最長公共子序列LCS


 

 

給定兩個序列X和Y,如果Z既是X的一個子序列又是Y的一個子序列,則稱序列Z是X和Y的一個公共子序列。

 

在最長公共子序列問題(LCS)中,給定了兩個序列X=<x1,x2,…,xm>和Y=<y1,y2,…,yn>,希望找出X和Y的最大長度的公共子序列。最直觀且容易想到的方法是枚舉出X的所有子序列,然后逐一檢查看其是否為Y的子序列,並隨時記錄所發現的最長子序列。這種方法的時間復雜度是指數級的,對於較長的序列來說是不實際的。

 

LCS問題的最優子結構:

 

若xm=yn,則zk=xm=yn且Zk-1是Xm-1和Yn-1的最長公共子序列;
若xm≠yn且zk≠xm ,則Z是Xm-1和Y的最長公共子序列;
若xm≠yn且zk≠yn ,則Z是X和Yn-1的最長公共子序列。

算法:LCS-LENGTH(X, Y)

 1  2 m ← length[X]
 3 n ← length[Y]
 4 for i ← 1 to m
 5       do c[i, 0] ← 0
 6 for j ← 0 to n
 7     do c[0, j] ← 0
 8 for i ← 1 to m
 9     do for j ← 1 to n
10             do if xi = yj
11                    then c[i, j] ← c[i - 1, j - 1] + 1
12                         b[i, j] ← ""
13                    else if c[i - 1, j] ≥ c[i, j - 1]
14                           then c[i, j] ← c[i - 1, j]
15                                b[i, j] ← ""
16                           else c[i, j] ← c[i, j - 1]
17                                b[i, j] ← ←
18 return c and b

C++實現:

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 
  5 using namespace std;
  6 
  7 enum
  8 dir {dInit = 0, dLeft, dUp, dUpLeft};//定義方向初始化值dInit,三個方向左dLeft、上dUp、左上dUpLeft
  9 
 10 void LCSPrint(int **LCS_direction, const char* la, const char* lb, int row, int col)
 11 {
 12     if (la == NULL || lb == NULL)
 13         return;
 14 
 15     int lengthA = strlen(la);
 16     int lengthB = strlen(lb);
 17 
 18     if (lengthA ==0 || lengthB == 0 || !(row < lengthA && col < lengthB))
 19         return;
 20 
 21     if (LCS_direction[row][col] == dUpLeft)
 22     {
 23         if (row > 0 && col > 0)
 24             LCSPrint(LCS_direction, la, lb, row - 1, col - 1);
 25 
 26         printf("%c", la[row]);
 27     }
 28     else if (LCS_direction[row][col] == dUp)
 29     {
 30         if (row > 0)
 31             LCSPrint(LCS_direction, la, lb, row - 1, col);
 32     }
 33     else if(LCS_direction[row][col] == dLeft)
 34     {
 35         if (col > 0)
 36             LCSPrint(LCS_direction, la, lb, row, col - 1);
 37     }
 38 }
 39 
 40 int
 41 LCSLength(const char *la, const char *lb)
 42 {
 43     if (!la || !lb)
 44         return 0;
 45 
 46     int lengthA = strlen(la);
 47     int lengthB = strlen(lb);
 48 
 49     if (!lengthA || !lengthB)
 50         return 0;
 51 
 52     int i, j;
 53 
 54     //創建並初始化存放長度的二維數組
 55     int **LCS_length;
 56     LCS_length = (int**)(new int[lengthA]);
 57     for (i = 0; i < lengthA; ++i)
 58         LCS_length[i] = (int*)new int[lengthB];
 59 
 60     for (i = 0; i < lengthA; ++i)
 61         for (j = 0; j < lengthB; ++j)
 62             LCS_length[i][j] = 0;
 63 
 64     //創建並初始化存放方向的二維數組,方向在枚舉enum dir中定義
 65     int **LCS_direction;
 66     LCS_direction = (int**)(new int[lengthA]);
 67     for (i = 0; i < lengthA; ++i)
 68         LCS_direction[i] = (int*)new int[lengthB];
 69 
 70     for (i = 0; i < lengthA; ++i)
 71         for (j = 0; j < lengthB; ++j)
 72             LCS_direction[i][j] = dInit;
 73 
 74     for (i = 0; i < lengthA; ++i)
 75     {
 76         for (j = 0; j < lengthB; ++j)
 77         {
 78             if (i == 0 || j == 0)
 79             {
 80                 if (la[i] == lb[j])
 81                 {
 82                     LCS_length[i][j] = 1;
 83                     LCS_direction[i][j] = dUpLeft;
 84                 }
 85                 else
 86                 {
 87                     if (i > 0)
 88                     {
 89                         //i > 0不是第一行
 90                         LCS_length[i][j] = LCS_length[i - 1][j];
 91                         LCS_direction[i][j] = dUp;
 92                     }
 93                     if (j > 0)
 94                     {
 95                         //j > 0不是第一列
 96                         LCS_length[i][j] = LCS_length[i][j - 1];
 97                         LCS_direction[i][j] = dLeft;
 98                     }
 99                 }
100             }
101 
102             else if (la[i] == lb[j])
103             {
104                 LCS_length[i][j] = LCS_length[i - 1][j - 1] + 1;
105                 LCS_direction[i][j] = dUpLeft;
106             }
107 
108             else if (LCS_length[i - 1][j] > LCS_length[i][j - 1])
109             {
110                 LCS_length[i][j] = LCS_length[i - 1][j];
111                 LCS_direction[i][j] = dUp;
112             }
113 
114             else
115             {
116                 LCS_length[i][j] = LCS_length[i][j - 1];
117                 LCS_direction[i][j] = dLeft;
118             }
119         }
120     }
121     LCSPrint(LCS_direction, la, lb, lengthA - 1, lengthB - 1);
122     cout << endl;
123     return LCS_length[lengthA - 1][lengthB - 1];
124 }
125 
126 int main()
127 {
128     const char* la = "ABCBDAB";
129     const char* lb = "BDCABA";
130     int length = LCSLength(la, lb);
131     cout << "最長子序列長度為:" << length << endl;
132     return 0;
133 }

Python實現:

 1 def LCS(la, lb):
 2     if la == "" or lb == "":
 3         return
 4     lengthA = len(la)
 5     lengthB = len(lb)
 6     lcs = [[0] for i in range(0, lengthA + 1)]
 7     lcs[0] = [0 for j in range(0, lengthB + 1)]
 8     for i in range(lengthA):
 9         for j in range(lengthB):
10             lcs[i + 1].append(lcs[i][j] + 1 if la[i] == lb[j] else max(lcs[i][j + 1], lcs[i + 1][j]))
11     i = lengthA - 1
12     j = lengthB - 1
13     lcsstr = ""
14     while True:
15         if i == -1 or j == -1:
16             break
17         if la[i] == lb[j]:
18             lcsstr = "%s%s" % (la[i], lcsstr)
19             i = i - 1
20             j = j - 1
21         else:
22             if lcs[i][j + 1] > lcs[i + 1][j]:
23                 i = i - 1
24             else:
25                 j = j - 1
26     print lcsstr
27     
28 LCS("ABCBDAB", "BDCABA")

 

 


免責聲明!

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



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