C++实现最长公共子序列和最长公共子串

来源:互联网 发布:java 相似度计算 编辑:程序博客网 时间:2024/05/29 02:27

C++实现最长公共子序列和最长公共子串

图1
图2

可能直接看上面的公式不是很能理解,下面这段话,应该很直白的解释了上面的公式,可以对比着理解下:

   Xi = <x1,x2,x3,....xi> 即X序列的前i个字符(1<= i <= m)(前缀)   Yj = <y1,y2,y3,....yi> 即Y序列的前j个字符(1<= j <= m)(前缀)

假定Z = <z1,z2,z3,...zk>是LCS(X,Y)中的一个。

·若xm = yn(最后一个字符相同),则不难用反正法证明:该字符必是X与Y的任一最长公共子序列Z(设长度为k)的最后一个字符,即有zk = xm = yn,且显然有Zk-1∈LCS(Xm-1,Yn-1),即Z的前缀Zk-1是Xm-1与Yn-1的最长公共子序列。此时,问题化归成求Xm-1与Yn-1的LCS(LCS(X,Y))的长度等于LCS(Xm-1,Yn-1)的长度加1)。
·若xm≠yn,则亦不难用反证法证明:要么Z∈LCS(Xm-1, Y),要么Z∈LCS(X , Yn-1)。由于zk≠xm与zk≠yn其中至少有一个必成立,若zk≠xm则有Z∈LCS(Xm-1 , Y);类似的,若zk≠yn 则有Z∈LCS(X , Yn-1)。此时,问题化归成求Xm-1与Y的LCS及X与Yn-1的LCS。LCS(X , Y)的长度为:max{LCS(Xm-1 , Y)的长度, LCS(X , Yn-1)的长度}。

版本一:这个版本对lcs的打印比较晦涩难懂,但是只要理解还是可以看懂。

#include <iostream>#include <string>#include <vector>#include <algorithm>using namespace std;int lcs( string &str1,string &str2,vector< vector<int> >& c ){    const int len1 = str1.length();    const int len2 = str2.length();    for( int i=0;i<=len1;++i )    {        for( int j=0;j<=len2;++j )        {            if( !i || !j ){                c[i][j] = 0;                continue;            }            if( str1[i-1] == str2[j-1] )            {                c[i][j] = c[i-1][j-1] + 1;            }            else            {                if( c[i-1][j] > c[i][j-1] )                {                    c[i][j] = c[i-1][j];                }                else                {                    c[i][j] = c[i][j-1];                }            }        }    }    return c[len1][len2];   }void print_lcs( string &str1,string &str2,vector< vector<int> >& c ){    const int len1 = str1.length();    const int len2 = str2.length();    for( int i=len1,j=len2;i>=1&&j>=1; )    {        if( str1[i-1] == str2[j-1] )        {            cout << " " << str1[i-1];            i--;            j--;            continue;        }        if( c[i-1][j] > c[i][j-1] )        {            i--;        }        else        {            j--;        }    }}int main(){    string str;    vector <string> v;    while( getline(cin,str) &&  !str.empty() )    {        v.push_back(str);    }    for( vector<string>::iterator iter = v.begin(); iter != v.end(); ++iter)    {        string str(*iter);        reverse(str.begin(),str.end());        vector< vector<int> > c( (*iter).length() + 1,vector<int>(str.length()+1,0) );        cout << str.length() - lcs(*iter,str,c) << endl;        print_lcs(*iter,str,c);    }    return 0;} 

版本二:对lcs的打印进行优化,创建二维数组来标示,后面的循环也改成递归方式。

#include <iostream>#include <string>#include <vector>#include <algorithm>using namespace std;int lcs( string &str1,string &str2,vector< vector<int> >& vec ){    const int len1 = str1.length();    const int len2 = str2.length();    vector< vector<int> > c( len1 + 1,vector<int>(len2+1,0) );    for( int i=0;i<=len1;++i )    {        for( int j=0;j<=len2;++j )        {            if( !i || !j ){                c[i][j] = 0;                continue;            }            if( str1[i-1] == str2[j-1] )            {                c[i][j] = c[i-1][j-1] + 1;                // 标示可打印该值                vec[i][j] = 0;            }            else            {                if( c[i-1][j] > c[i][j-1] )                {                    c[i][j] = c[i-1][j];                    // 标示i值减一,即向上(i表示行,j表示列)                    vec[i][j] = 1;                }                else                {                    c[i][j] = c[i][j-1];                    // 标示j值减一,即向左(i表示行,j表示列)                    vec[i][j] = 2;                }            }        }    }    return c[len1][len2];   }void print_lcs(vector< vector<int> >& vec,string str,int i,int j){    if( !i || !j )        return;    // 根据上面的标示来即可    if( !vec[i][j] )    {        cout << " " << str[i-1] << " ";        print_lcs(vec,str,i-1,j-1);    }    else if( vec[i][j] == 1 )    {        print_lcs(vec,str,i-1,j);    }    else if( vec[i][j] == 2 )    {        print_lcs(vec,str,i,j-1);    } }int main(){    string str;    vector <string> v;    while( getline(cin,str) &&  !str.empty() )    {        v.push_back(str);    }    for( vector<string>::iterator iter = v.begin(); iter != v.end(); ++iter)    {        string str(*iter);        reverse(str.begin(),str.end());        vector< vector<int> > vec( (*iter).length() + 1,vector<int>(str.length()+1,-1) );        cout << str.length() - lcs(*iter,str,vec) << endl;        print_lcs(vec,str,(*iter).length(),str.length());        cout << endl;    }    return 0;}

图2

#include <iostream>#include <string>#include <vector>#include <algorithm>using namespace std;int lcs( string &str1,string &str2,vector< vector<int> >& vec ){    int result = 0;    const int len1 = str1.length();    const int len2 = str2.length();    vector< vector<int> > c( len1 + 1,vector<int>(len2+1,0) );    for( int i=0;i<=len1;++i )    {        for( int j=0;j<=len2;++j )        {            if( !i || !j ){                c[i][j] = 0;                continue;            }            if( str1[i-1] == str2[j-1] )            {                c[i][j] = c[i-1][j-1] + 1;                vec[i][j] = 0;                result = c[i][j] > result ? c[i][j] : result;            }        }    }    return result;   }int main(){    string str;    vector <string> v;    while( getline(cin,str) &&  !str.empty() )    {        v.push_back(str);    }    for( vector<string>::iterator iter = v.begin(); iter != v.end(); ++iter)    {        string str(*iter);        reverse(str.begin(),str.end());        vector< vector<int> > vec( (*iter).length() + 1,vector<int>(str.length()+1,-1) );        cout << str.length() - lcs(*iter,str,vec) << endl;    }    return 0;} 

参考资料:点击打开链接