最长公共子串是字符串匹配中一个常见问题,在此做下总结,感觉解法真的是很巧妙。
如:对于字符串“aabbaadcc”和“baadce”,矩阵中,m[i][j] = 1,表示str1[i]和str2[j]相等
a a b b a a d c c
b 0 0 1 1 0 0 0 0 0
a 1 1 0 0 1 1 0 0 0
a 1 1 0 0 1 1 0 0 0
d 0 0 0 0 0 0 1 0 0
c 0 0 0 0 0 0 0 1 1
e 0 0 0 0 0 0 0 0 0
由于是找最长公共子串,其实相当于找全为1的最长的斜对角线。
其实,统计斜对角线也是麻烦的事情,若每一行m[i][j]变为以str1[i]和str2[j]结尾的子串的最长公共子串长度,由于公共子串
必须连续,故变为m[i][j] = (str1[i] == str2[j]? m[i-1]+1 : 0)。这样,每次统计仅需用到上一行数据,也无需用一个矩阵来保存了。
【由于矩阵转置后,不影响斜对角线的统计,故字符串顺序其实可颠倒】
a a b b a a d c c
b 0 0 1 1 0 0 0 0 0
a 1 1 0 0 2 1 0 0 0
a 1 2 0 0 1 3 0 0 0
d 0 0 0 0 0 0 4 0 0
c 0 0 0 0 0 0 0 5 1
e 0 0 0 0 0 0 0 0 0
故,代码如下
1 /* 2 最长公共子串【连续】 3 */ 4 #include "stdafx.h" 5 #include <iostream> 6 #include <vector> 7 #include <string>
8 9 using namespace std; 10 11 const string LCS(const string &str1,const string &str2) 12 { 13 int s1len = str1.size(); //横向长度 14 int s2len = str2.size(); //纵向长度 15 vector<int> temp(s1len); //保存矩阵上一行 16 vector<int> current(s1len); //当前行 17 int max = 0; //当前矩阵中最大值 18 int pos = 0; //矩阵最大值出现在第几列 19 20 for(int i = 0; i<s2len; i++) 21 { 22 //string s = str2.substr(i,1);; 23 current.assign(s1len,0); 24 for(int j=0; j<s1len; j++) 25 { 26 if(str1[j]== str2[i]) 27 { 28 if(j==0)//第一列,无前驱元素 29 current[j]= 1; 30 else 31 current[j] = temp[j-1] + 1; 32 if(current[j] > max) 33 { 34 max = current[j]; 35 pos = j; 36 } 37 } 38 } 39 temp.assign(current.begin(),current.end()); 40 } 41 string res = str1.substr(pos-max+1,max);//公共子串很巧妙 42 return res; 43 } 44 45 int main() 46 { 47 string str1("acbac"); 48 string str2("acaccbabb"); 49 string lcs = LCS(str1,str2); 50 cout << lcs << endl; 51 52 return 0; 53 }
参考:http://www.cnblogs.com/zhangchaoyang/articles/2012070.html