• 算法实践--最长公共子序列(Longest Common Subsquence)


    什么是最长公共子序列

    X=ACCG

    Y=CCAGCA

    长度为1的公共子序列: {A} {C} {G}

    长度为2的公共子序列:{AC} {CC} {CG} {AG}

    长度为3的公共子序列:{ACG}

    长度为4的公共子序列

    最长公共子序列即为 {ACG}

    问题:长度为N和M的两个序列如何求他们的最长公共子序列?

    X = ACCGGGTTACCGTTTAAAACCCGGGTAACCT

     

    Y = CCAGGACCAGGGACCGTTTACCAGCCTTAAACCA

     

    简单算法

    for (int i=N; i>0; --i) {

      找到X所有长度为i的子序列;

      找到Y所有长度为i的子序列;

      如果存在公共子序列则终止

    }

    复杂度O(2^N)

    动态规划算法

    定义C[i][j]为序列X[i..i]和Y[1..j]的最长子序列的长度

    C[i][0]和C[0][j]==0

    递推公式

    C[i][j]=C[i-1][j-1]+1,  X[i]==Y[j]

    C[i][j]=MAX(C[i-1][j], C[i][j-1]),  X[i]!=Y[j]

    C++实现

    template<typename T>
    void prtM(vector< vector<T> >& arr, string msg = "") {
        cout << msg << " " << endl;
        for  (auto i: arr) {
            for (auto j: i) {
                cout << j << " ";
            }
            cout << endl;
        }
        cout << endl;
    }
    
    template <typename T>
    void prt(vector<T>& arr, string msg = "") {
        cout << msg << " ";
        for  (auto i: arr) {
            cout << i << " ";
        }
        cout << endl;
    }
    
    
    void prt_LCS(vector< vector<char> >& S, string& X, int i, int j) { // 递归调用
        //cout << "i=" << i << " j=" << j << "  " << S[i][j] << endl;
        if (i==0 || j == 0)
            return;
        if ('s' == S[i][j]) {
            prt_LCS(S, X, i-1, j-1);
            cout << X[i];
        } else if ('j' == S[i][j])  {
            prt_LCS(S, X, i, j-1);
        } else {
            prt_LCS(S, X, i-1, j);
        }
    }
    
    
    void calc_LCS(string& X,  string& Y) {
        cout << "X: " << X << endl;
        cout << "Y: " << Y << endl;
    
        vector< vector<int> > C;  // 序列X[0..i] and Y[0..j]的公共子序列的长度
        vector< vector<char> > S;  //最长公共子串的位置
        for (int i=0; i<X.size(); i++) {
            C.push_back( vector<int>(Y.size()) );  
            S.push_back( vector<char>(Y.size()) );
        }
    
        for (int i=0; i<X.size(); i++) 
            C[i][0] = 0;
        for (int j=0; j<Y.size(); j++) 
            C[0][j] = 0;
    
        for (int i=1; i<X.size(); i++)
            for (int j=1; j<Y.size(); j++) {
                if (X[i] == Y[j]) {
                   C[i][j] = C[i-1][j-1] + 1;
                   S[i][j] = 's';  // 相同,可以打印
                } else if ( C[i][j-1] > C[i-1][j] ) {
                    C[i][j] = C[i][j-1];
                    S[i][j] = 'j';  //Y的最后一个可以去掉,不影响LCS
                } else {
                    C[i][j] = C[i-1][j] ;
                    S[i][j] = 'i';  //X的最后一个可以去掉,不影响LCS
                }
            }
    
        prtM(C);
        prtM(S);
        prt_LCS(S, X, X.size()-1, Y.size()-1);
        cout<< endl;
    }
    
    int main() {
    
        string S1 = " ACCGGGTTAC";  // 为了方便表示,忽略第一个字符
        string S2 = " AGGACCA";
    
        calc_LCS(S1, S2);
    
        return 0;
    }
  • 相关阅读:
    国王游戏
    从2014到2015,还有什么?
    【转载】别把自己推到了墙角
    IE9+浏览器input文本框/密码框后面的小叉子/小眼睛清除
    ajax开发模拟后端数据接口
    谈谈JavaScript事件
    也说border-box盒模型
    极其简单的使用基于gulp和sass前端工作流
    如何使用javascript书写递归函数
    Git基本命令和GitFlow工作流
  • 原文地址:https://www.cnblogs.com/logchen/p/10264927.html
Copyright © 2020-2023  润新知