最长公共子序列和子串—DP

最长公共子序列

1).子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串
cnblogs
belong
比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与母串保持一致,我们将其称为公共子序列。最长公共子序列(Longest Common Subsequence,LCS),顾名思义,是指在所有的子序列中最长的那一个。子串是要求更严格的一种子序列,要求在母串中连续地出现。在上述例子的中,最长公共子序列为blog(cnblogs,belong),最长公共子串为lo(cnblogs, belong)。
2). 求解算法对于母串X=, Y=,求LCS与最长公共子串。
暴力解法
假设 m
动态规划
假设Z=是X与Y的LCS, 我们观察到
如果Xm=Yn,则Zk=Xm=Yn,有Zk−1是Xm−1与Yn−1的LCS;
如果Xm≠Yn,则Zk是Xm与Yn−1的LCS,或者是Xm−1与Yn的LCS。
因此,求解LCS的问题则变成递归求解的两个子问题。但是,上述的递归求解的办法中,重复的子问题多,效率低下。改进的办法——用空间换时间,用数组保存中间状态,方便后面的计算。这就是动态规划(DP)的核心思想了。
DP求解LCS
用二维数组c[i][j]记录串x1x2⋯xi与y1y2⋯yj的LCS长度,则可得到状态转移方程
这里写图片描述

代码实现

 int findLCS(string A, int n, string B, int m) {
        if(A.empty() || B.empty() || n == 0 || m == 0)
            return 0;
        vector<vector<int>> num(n+1, vector<int>(m+1));
        for(int i = 0; i <= n; i++){
            for(int j = 0; j <= m; j++){
                if(i == 0 || j == 0)
                    num[i][j] = 0;
                else if(A[i-1] == B[j-1])
                    num[i][j] = num[i-1][j-1] + 1;
                else
                    num[i][j] = max(num[i-1][j], num[i][j-1]);
            }
        }
        return num[n][m];
    }

最长公共子串

前面提到了子串是一种特殊的子序列,因此同样可以用DP来解决。定义数组的存储含义对于后面推导转移方程显得尤为重要,糟糕的数组定义会导致异常繁杂的转移方程。考虑到子串的连续性,将二维数组c[i][j]用来记录具有这样特点的子串——结尾同时也为为串x1x2⋯xi与y1y2⋯yj的结尾——的长度。
得到转移方程:
这里写图片描述

最长公共子串的长度为 max(c[i,j]), i∈{1,⋯,m},j∈{1,⋯,n}。
代码实现

    int findLongest(string A, int n, string B, int m) {
        if(A.empty() || B.empty() || n == 0 || m == 0)
            return 0;
        vector<vector<int>> num(n+1, vector<int>(m+1));
        int result = 0;
        for (int i = 0; i <= n; i++){
            for(int j = 0; j <= m; j++){
                if (i == 0 || j == 0)
                        num[i][j] = 0;
               else if(A[i-1] == B[j-1]){
                    num[i][j] = num[i - 1][j - 1] + 1;
                    result = max(result, num[i][j]);
               }else
                   num[i][j] = 0;
            }
        }
           return result;
        // write code here
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值