首页 > 代码库 > 最长公共子串+最长公共子序列

最长公共子串+最长公共子序列

两道题都可以用动态规划的方法做,只是状态转移方程不同。

 

最长公共子串(注意子串是连续的)

1、先建立一个二维数组array[str1.size()][str2.size()](全部初始化为0),初始化第一行和第一列(元素相同处置1),然后进入状态方程

2、状态转移方程:

  if(str1[i] == str2[i])   array[i][j]=array[i-1][j-1]+1;  (左上方对角线的值加上1)

  否则无操作。

3、最后寻找整个array中的最大值即可(因为可能有多个子串)

 1 /* 2 本程序说明: 3   4 最长公共子串(注意空格,不要用cin,要用getline) 5   6 */ 7 #include <iostream> 8 #include <vector> 9 #include <string>10 using namespace std;11  12 int largestCommentSubString(std::string str1,std::string str2){13     if(0 == str1.length() || 0 == str2.length())14         return 0;15  16     std::vector<std::vector<int> > array(str1.size(),std::vector<int>(str2.size(),0));17     for(size_t i=0; i< str2.size(); ++i){18         if(str1[0] == str2[i])19             array[0][i]=1;20     }21     for(size_t i=0; i< str1.size(); ++i){22         if(str2[0] == str1[i])23             array[i][0]=1;24     }25     for(size_t i=1; i< str1.size(); ++i){26         for(size_t j=1; j< str2.size(); ++j){27             if(str1[i] == str2[j]){28                 array[i][j]=array[i-1][j-1]+1;29             }30         }31     }32     int length=0;33     for(size_t i=0; i< array.size(); ++i){34         for(size_t j=0; j< array[0].size(); ++j){35             if(array[i][j]>length){36                 length=array[i][j];37             }38         }39     }40     return length;41 }42  43 int main(){44     std::string str1,str2;45     while(getline(cin,str1),getline(cin,str2)){     46         cout<<largestCommentSubString(str1,str2)<<endl;47     }48     return 0;49 }

 

最长公共子序列(注意子序列可以不连续)

1、先建立一个二维数组array[str1.size()+1][str2.size()+1](全部初始化为0),然后进入状态方程

2、状态转移方程:

  if(str1[i] == str2[i])   array[i][j]=array[i-1][j-1]+1; (左上方对角线的值加上1)

  if(str1[i] != str2[i])   array[i][j]=max(array[i-1][j],array[i][j-1]);  (左边和上边的最大值)

3、最后返回整个array中的最大值即可(即array右下角元素的值)

 1 /* 2 本程序说明: 3  4 最长公共子序列 5  6 */ 7 #include <iostream> 8 #include <vector> 9 #include <string>10 using namespace std;11 12 int findLCS(string str1,string str2) {13     // write code here14     if(0 == str1.size() || 0 == str2.size())15         return 0;16     vector<vector<int> > array(str1.size()+1,vector<int>(str2.size()+1,0));17     for(size_t i=1; i<= str1.size(); ++i){//注意:是小于等于18         for(size_t j=1; j<= str2.size(); ++j){//注意:是小于等于19             if(str1[i-1] == str2[j-1]){//前面填充了一行一列,因此判断i-1和j-120                 array[i][j]=array[i-1][j-1]+1;21                 }22             else23                 array[i][j]=max(array[i-1][j],array[i][j-1]);24         }25     }26     return array[str1.size()][str2.size()];27 }28 29 int main(){30     string str1,str2;31     while(getline(cin,str1),getline(cin,str2)){32         cout<<findLCS(str1,str2)<<endl;33     }34     return 0;35 }

 

如果还要进一步打印出其中一个公共子序列的话,需要用到回溯法。我们在动态规划时需要记录元素的状态,一步步回溯回去即可。

 1 /* 2 本程序说明: 3  4 最长公共子序列(加上了其中一个子序列的打印功能,回溯法) 5  6 */ 7 #include <iostream> 8 #include <vector> 9 #include <string>10 using namespace std;11 12 //打印(回溯法)13 void printLCS(const string& str1,const string& str2,const vector<vector<string> >& flag,int i,int j,string& str)14 {15     if(0==i||0==j)16         return;17     if("left_up"==flag[i][j])18     {19         str.insert(str.begin(),str1[i-1]);//把要打印的公共字符逆序存在str中(因为回溯法从后向前,所以需要逆序)20         printLCS(str1,str2,flag,i-1,j-1,str);21     }22     else if("left"==flag[i][j])23         printLCS(str1,str2,flag,i-1,j,str);24     else if("up"==flag[i][j])25         printLCS(str1,str2,flag,i,j-1,str);26 }27 28 int findLCS(const string& str1,const string& str2) {29     // write code here30     if(0 == str1.size() || 0 == str2.size())31         return 0;32     vector<vector<string> > flag(str1.size()+1,vector<string>(str2.size()+1,""));//记录状态33     vector<vector<int> > array(str1.size()+1,vector<int>(str2.size()+1,0));34     for(size_t i=1; i <= str1.size(); ++i){//注意:是小于等于35         for(size_t j=1; j<= str2.size(); ++j){//注意:是小于等于36             if(str1[i-1] == str2[j-1]){//前面填充了一行一列,因此判断i-1和j-137                 array[i][j] = array[i-1][j-1]+1;38                 flag[i][j] = "left_up";39             }40             else41             {42                 if(array[i-1][j] > array[i][j-1])43                 {44                     array[i][j] = array[i-1][j];45                     flag[i][j] = "left";46                 }47                 else/*(array[i-1][j] < array[i][j-1])*/48                 {49                     array[i][j] = array[i][j-1];50                     flag[i][j] = "up";51                 }52             }53         }54     }55 56     string str="";57     printLCS(str1,str2,flag,str1.size(),str2.size(),str);58     cout<<"公共子序列: "<<str<<endl;59     return array[str1.size()][str2.size()];60 }61 62 int main(){63     std::string str1,str2;64     while(getline(cin,str1),getline(cin,str2)){65         cout<<findLCS(str1,str2)<<endl;66     }67     return 0;68 }

 

参考文章:http://www.cnblogs.com/huangxincheng/archive/2012/11/11/2764625.html

最长公共子串+最长公共子序列