最长公共子序列 [动态规划]
题目:如果字符串一的所有字符按其在字符串中的顺序出现在另外一个字符串二中,则字符串一称之为字符串二的子串。注意,并不要求子串(字符串一)的字符必须连续出现在字符串二中。请编写一个函数,输入两个字符串,求它们的最长公共子串,并打印出最长公共子串。
例如:输入两个字符串BDCABA和ABCBDAB,字符串BCBA和BDAB都是是它们的最长公共子串,则输出它们的长度4,并打印任意一个子串。
分析:求最长公共子串(Longest Common Subsequence, LCS)是一道非常经典的动态规划题,因此一些重视算法的公司像MicroStrategy都把它当作面试题。
这个问题的详细分析见《算法导论》15.4节
状态转移方程:
回溯输出最长公共子序列过程:
1 /* 2 Author: Tanky Woo 3 Blog: www.WuTianQi.com 4 About: 《算法导论》15.4 最长公共自序列(LCS) 5 */ 6 7 #include <iostream> 8 using namespace std; 9 10 char b[20][20]; 11 int c[20][20]; 12 13 char x[20], y[20]; 14 15 void LCS() 16 { 17 int m = strlen(x+1); 18 int n = strlen(y+1); 19 20 for(int i=1; i<=m; ++i) 21 c[i][0] = 0; 22 for(int j=1; j<=n; ++j) 23 c[0][j] = 0; 24 25 for(int i=1; i<=m; ++i) 26 for(int j=1; j<=n; ++j) 27 { 28 if(x[i] == y[j]) 29 { 30 c[i][j] = c[i-1][j-1] + 1; 31 b[i][j] = '\\'; // 注意这里第一个\\是转移字符,代表\ 32 } 33 else if(c[i-1][j] >= c[i][j-1]) 34 { 35 c[i][j] = c[i-1][j]; 36 b[i][j] = '|'; 37 } 38 else 39 { 40 c[i][j] = c[i][j-1]; 41 b[i][j] = '-'; 42 } 43 } 44 } 45 46 void printLCS(int i, int j) 47 { 48 if(i == 0 || j == 0) 49 return; 50 if(b[i][j] == '\\') 51 { 52 printLCS(i-1, j-1); 53 cout << x[i] << " "; 54 } 55 else if(b[i][j] == '|') 56 printLCS(i-1, j); 57 else 58 printLCS(i, j-1); 59 } 60 61 int main() 62 { 63 cout << "Input the array A:\n"; 64 cin >> x+1; 65 cout << "Input the array B:\n"; 66 cin >> y+1; 67 LCS(); 68 printLCS(strlen(x+1), strlen(y+1)); 69 }
以上分别参考何海涛博客和http://www.cnblogs.com/tanky_woo/archive/2011/05/26/2059116.html