• 动态规划-最长公共子序列LCS


    0 问题

    给定两个字符串,求最长公共子序列LCS。

    也就是说两个字符串中都有的部分,或者理解为,两个字符串同时都删除字符串中的某些字符,使得最终的两个字符串,相等,且是最长的。

    1 分析

    假设两个str1,str2字符串,已经知道了最长公共子序列长度为L

    那么,当在str1和str2,两个的尾部,同时添加一个相同的字符,比如a,那么新的str1,和str2的最长公共子序列长度就是L+1

    当str1后面添加一个字符,str2不添加,那么最长公共子序列长度为L

    反之,str1不添加,str2添加,那么也是L

    当同时添加一个字符,但是添加不同的字符,那么长度仍为L

    因此,可以考虑

    int lcs(string str1, string str2)
    {
        int len1 = str1.size();
        int len2 = str2.size();
    
        // memo[i][j] 中记录的是,字符串从第0个字符开始,长度为i,或是j的子数组的lcs长度
        vector<vector<int>> memo(len1 + 1, vector<int>(len2 + 1, 0));
    
        // i,j都是长度,表示从第0个字符开始长为i或j的子字符串
        // 因此使用的是 str1[i - 1] == str2[j - 1] 来比较
        // i,j都不断的递增,则可认为是不断的添加字符
        for (int i = 1; i <= str1.size(); ++i)
        {
            for (int j = 1; j <= str2.size(); ++j)
            {
                if (str1[i - 1] == str2[j - 1])
                {
                    // 当两个字符相同的时候,就认为,是比之前的子数组的lcs长度大1
                    memo[i][j] = memo[i - 1][j - 1] + 1;
                }
                else
                {
                    // 如果新添加的两个字符不相同,那么取之前的 L 
                    // 但是可能是str1 加字符得来的,也可能是str2 加字符得来的,因此需要取两个前状态的lcs的长度最大值
                    if (memo[i - 1][j] > memo[i][j - 1])
                    {
                        memo[i][j] = memo[i - 1][j];
                    }
                    else
                    {
                        memo[i][j] = memo[i][j - 1];
                    }
                }
            }
        }
        return memo[len1][len2];
    }
    

      

    或者说,也可以这样考虑,

    str1,和str2,当最后一个字符相同,那么,str1,和str2的最长公共子序列的长度应该是,str-1和str2-1的最长公共子序列长度+1

    当最后一个字符不相同的时候,那么,str1,和str2的最长公共子序列的长度应该是(str1-1和str2)与(str1和str2-1)的最长公共子序列长度的较大的那个。

    但是这样计算大量相同的问题,因此加上memo

    int aux_lcs_d(string str1, int l1, string str2, int l2,vector<vector<int>> &memo)
    {
        if (l1 < 0 || l2 < 0)
        {
            return 0;
        }
        if(memo[l1][l2] != 0)
        {
            return memo[l1][l2];
        }
        if (str1[l1] == str2[l2])
        {
            memo[l1][l2]= aux_lcs_d(str1, l1 - 1, str2, l2 - 1,memo) + 1;
            return memo[l1][l2];
        }
        else
        {
            memo[l1][l2]= max(aux_lcs_d(str1, l1, str2, l2 - 1,memo), aux_lcs_d(str1, l1 - 1, str2, l2,memo));
            return memo[l1][l2];
        }
    }
    
    int lcs_d(string str1,string str2)
    {
        vector <vector<int>> memo(str1.size(),vector<int>(str2.size(),0));
        return aux_lcs_d(str1, str1.size()-1, str2, str2.size()-1,memo) ;
    }
    

      

    以上就是计算lcs长度的思路.

    当需要计算出完成的路径时。添加一个额外的容器,记录,每个状态是怎么从前一个状态转移过来的

    int aux_lcs_d(string str1, int l1, string str2, int l2,vector<vector<int>> &memo,vector<vector<int>> &path)
    {
        if (l1 < 0 || l2 < 0)
        {
            return 0;
        }
        if(memo[l1][l2] != 0)
        {
            
            return memo[l1][l2];
        }
        if (str1[l1] == str2[l2])
        {
            path[l1][l2]='0'; // 这个表示从str1 ,str2同时增长来的
            memo[l1][l2]= aux_lcs_d(str1, l1 - 1, str2, l2 - 1,memo,path) + 1;
            return memo[l1][l2];
        }
        else
        {
            int tmp1=aux_lcs_d(str1, l1, str2, l2 - 1,memo,path);
            int tmp2=aux_lcs_d(str1, l1 - 1, str2, l2,memo,path);
            memo[l1][l2]= max(tmp1,tmp2);
            
            if(tmp1==memo[l1][l2])
            {
                // 表示从 str2 增长来的
                path[l1][l2]='2';
            }else{
                // 从str1 增长来的
                path[l1][l2]='1';
            }
            return memo[l1][l2];
        }
    }
    

      

      

  • 相关阅读:
    【python】Python 资源大全中文版
    获取最新chromedriver.exe的方法,并查阅最新的chromedriver.exe支持到什么chrome版本
    appium 重新启动apk
    git 命令操作
    [转]IDEA 出现编译错误 Multi-catches are not supported a this language level 解决方法
    jmeter压测前清理内存
    清理kafka zookeeper
    windows 自动移动maven jar包到jmeter 文件夹下面
    jmeter 压测duobbo接口,施压客户端自己把自己压死了
    kafak manager + zookeeper + kafka 消费队列快速清除
  • 原文地址:https://www.cnblogs.com/perfy576/p/8600747.html
Copyright © 2020-2023  润新知