最长公共子串(LCS)

  最长公共子串是字符串匹配中一个常见问题,在此做下总结,感觉解法真的是很巧妙。

  如:对于字符串“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

原文地址:https://www.cnblogs.com/dreamrun/p/4390082.html