zoukankan      html  css  js  c++  java
  • 动态规划之最长公共子序列

    首先需要说一下的是,什么是公共子序列。子串的概念就是,一个字符串中连续的一部分, 而 子序列,可以是不连续的。

    •一个给定序列的子序列是在该序列中删去若干元素后得到的序列。
    •给定两个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
    •最长公共子序列:公共子序列中长度最长的子序列。
    【穷举法】
    •对于每一个Xm的子序列,验证它是否是Yn的子序列.
    •Xm有2m个子序列
    •每个子序列需要o(n)的时间来验证它是否是Yn的子序列.
    –从Yn的第一个字母开始扫描下去,如果不是则从第二个开始
    •运行时间: o(2^n*2^m)
     
     
    【动态规划】
    •两个字符串【横向,纵向排列】
    ABDTFGHFEABADG
    BTHEBDCEFG
       A B DT F G H F EA B A D G
    B 0 1 1 1 1 1 1 1 1 1 1 1 1 1
    T 0 1 1 2 2 2 2 2 2 2 2 2 2 2
    H 0 1 1 2 2 2 3 3 3 3 3 3 3 3
    E 0 1 1 2 2 2 3 3 4 4 4 4 4 4
    B 0 1 1 2 2 2 3 3 4 4 5 5 5 5
    D 0 1 2 2 2 2 3 3 4 4 5 5 6 6
    C 0 1 2 2 2 2 3 3 4 4 5 5 6 6
    E 0 1 2 2 2 2 3 3 4 4 5 5 6 6
    F 0 1 2 2 3 3 3 4 4 4 5 5 6 6
    G 0 1 2 2 3 4 4 4 4 4 5 5 6 7

    状态迁移方程:

    c[i][j] 是用来保存截止到X[i],Y[j]的时候的最长公共子序列的长度。

    c[i][j] =0,                                  i = j =0;

    c[i][j] = c[i-1][j-1]+1 ,               i>0,j>0 && Xi = Yj

    c[i][j] = max(c[i-1][j],c[i][j-1]),  i>0,j>0 && Xi ≠ Yj

    #include<iostream>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int maxn = 1000;
    string str1,str2;
    int c[maxn][maxn];
    int n;int m;
    void solve()
    {
    
        for(int i = 0;i<n;i++)
        {
    
            for(int j = 0;j<m;j++)
            {
                if(str1[i] ==str2[j])
                    c[i+1][j+1] = c[i][j] + 1;
               else
               c[i+1][j+1] = max(c[i+1][j],c[i][j+1]);
            }
        }
    
    }
    
    int main()
    {
        cin>>str1>>str2;
         n = str1.length();
         m = str2.length();
        solve();
        cout<<c[n][m]<<endl;
    
        return 0;
    }
    

     后来仔细想想,没那么复杂其实也,只要自己肯动脑子……

    昨天晚上那个心急啊,想想该如何输出其中的一个最大公共子序列呢……

    矩阵 b[i, j]:存放当前的路径,也就是说c[i][j]是如何得来的。

    如果c[i][j] = c[i-1][j-1] 也就是对角线的关系;b[i][j] 标记为 '↖' b[i][j]  = 'S';

    如果c[i][j] = c[i][j-1] 也就是左右的关系 ,b[i][j] 标记为 '←' b[i][j]  = 'L';

    如果c[i][j] = c[i-1][j] 也就是上下的关系,b[i][j] 标记为 '↑' b[i][j]  = 'U';

     例如:

      B D C A B A

    A U U U S L S
    B S  L L U S L
    C U U S L U U
    B S U U U S L
    D U S U U U U
    A U U U S U S
    B S U U U S U

    从最后一个开始查找 U→S→U→S→L→S→L→S其中S对应的str1的元素就是其中的一条最长公共子子序列。

    使用递归的办法,遇到一个S就压入栈……

    #include<iostream>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int maxn = 1000;
    string str1,str2;
    int c[maxn][maxn];
    char b[maxn][maxn];
    int n;int m;
    void printLCS(int i, int j)
    
    {
    
        if(i==0 || j==0)
    
            return;
    
        if(b[i][j] == 'S')
    
        {
    
            printLCS(i-1, j-1);
    
            cout<<str1[i-1]<<' ';
    
        }
    
        else
    
        {
    
            if(b[i][j] == 'U')
    
                printLCS(i-1, j);
    
            else
    
                printLCS(i, j-1);
    
        }
    
    }
    void solve()
    {
    
        for(int i = 0;i<n;i++)
        {
    
            for(int j = 0;j<m;j++)
            {
                if(str1[i] ==str2[j])
                {
                    c[i+1][j+1] = c[i][j] + 1;
                    b[i+1][j+1] = 'S';
                }
               else if(c[i+1][j]>c[i][j+1])
               {
                    c[i+1][j+1] = c[i+1][j];
                    b[i+1][j+1] = 'L';
               }
               else
               {
                    c[i+1][j+1] = c[i][j+1];
                    b[i+1][j+1] = 'U';
               }
            }
        }
    
    }
    
    int main()
    {
        cin>>str1>>str2;
         n = str1.length();
         m = str2.length();
        solve();
        cout<<c[n][m]<<endl;
        for(int i = 1;i<=n;i++)
        {
            for(int j = 1;j<=m;j++)
                cout<<c[i][j]<<' ';
            cout<<endl;
        }
        for(int i = 1;i<=n;i++)
        {
            for(int j = 1;j<=m;j++)
                cout<<b[i][j]<<' ';
    
            cout<<endl;
        }
        printLCS(n,m);
    
        return 0;
    }
    
  • 相关阅读:
    107. Binary Tree Level Order Traversal II
    103. Binary Tree Zigzag Level Order Traversal
    102. Binary Tree Level Order Traversal
    690. Employee Importance
    1723. Find Minimum Time to Finish All Jobs
    LeetCode 329 矩阵中最长增长路径
    7.2 物理内存管理
    LeetCode 面试题 特定深度节点链表
    LeetCode 100 相同的树
    npm安装包命令详解,dependencies与devDependencies实际区别
  • 原文地址:https://www.cnblogs.com/plxx/p/3235440.html
Copyright © 2011-2022 走看看