leetcode 1143 最长公共子序列(DP)

题目描述
给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。

一个字符串的 子序列 是指这样一个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

例如,“ace” 是 “abcde” 的子序列,但 “aec” 不是 “abcde” 的子序列。
两个字符串的 公共子序列 是这两个字符串所共同拥有的子序列。

示例 1:
输入:text1 = “abcde”, text2 = “ace”
输出:3
解释:最长公共子序列是 “ace” ,它的长度为 3 。
示例 2:
输入:text1 = “abc”, text2 = “abc”
输出:3
解释:最长公共子序列是 “abc” ,它的长度为 3 。
示例 3:
输入:text1 = “abc”, text2 = “def”
输出:0
解释:两个字符串没有公共子序列,返回 0 。

使用动态规划,dp[i][j]表示在text1的前 i 个字符与text2的前 j 个字符之间最大公共子序列的长度。

  • 如果 text1[i] == text2[j] ,那么可以由dp[i-1][j-1]转化而来
  • 如果二者不相等,就要看text1[0 ~ i-1] 与 text2[0 ~ j] 以及 text1[0 ~ i ] 与 text2[0 ~ j-1] 这两者哪个公共子序列最大。
  • 边界条件,如果 i== 0 那么 dp[i][j]=0, 如果j==0,那么dp[i][j]=0,可以在初始化的时候将数组边界条件处理掉。
  • 最后输出的是dp[n][m]

为了减少判断条件,循环下标从1开始。

class Solution {
public:
    int longestCommonSubsequence(string text1, string text2) {
        int n=text1.size(),m=text2.size();
        vector<vector<int>> dp(n+1,vector<int>(m+1,0));
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(text1[i-1]==text2[j-1]) dp[i][j]=dp[i-1][j-1]+1;
                else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
            }
        }
        return dp[n][m];
    }
};

变种:NC127 最长公共子串
描述
给定两个字符串str1和str2,输出两个字符串的最长公共子串
题目保证str1和str2的最长公共子串存在且唯一。
示例1
输入:“1AB2345CD”,“12345EF”
返回值: “2345”

注意:子串是连续的,子序列是不连续的,因此动态规划方程也发生了一定的变化。
dp[i][j]表示字符串str1中第i个字符和str2种第j个字符为最长公共子串的最后一个元素。如果要求dp[i][j],也就是str1的第i个字符和str2的第j个字符为最后一个元素所构成的最长公共子串。
因此如果str1[i]!=str2[j]那么说明无法构成公共子串了,因此此时的值是0。
由于题目中要求返回最长公共子串,需要在计算过程中记录最长公共子串的结束位置以及子串的长度。

class Solution {
public:
    /**
     * longest common substring
     * @param str1 string字符串 the string
     * @param str2 string字符串 the string
     * @return string字符串
     */
    string LCS(string str1, string str2) {
        // write code here
        int n = str1.size(),m=str2.size();
        vector<vector<int>> dp(n+1,vector<int>(m+1,0));
        int len=0,pos=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=1;j<=m;j++)
            {
                if(str1[i-1]==str2[j-1]) dp[i][j]=dp[i-1][j-1]+1;
                if(dp[i][j]>len)
                {
                    len=max(len,dp[i][j]);
                    pos=i-1;
                }
            }
        }
        if(len==0) return "-1";
        return str1.substr(pos-len+1,len);
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值