【DP】【LCS】最长公共子序列及其应用

  LCS 是很经典的 DP 问题,很多公司面试都会考,也有很多问题可以用 LCS 解决:

  1. LeetCode - 1143. Longest Common Subsequence 最长公共子序列(就是 LCS
  2. LeetCode - 583. Delete Operation for Two Strings 将两个字符串删除为相同字符串最少删除字符数
  3. LeetCode - 516. Longest Palindromic Subsequence 最长回文子序列(LPS
  4. LeetCode - 1092. Shortest Common Supersequence 最短公共超序列
一、Longest Common Subsequence(LCS)

Given two strings text1 and text2, return the length of their longest common subsequence.
A subsequence of a string is a new string generated from the original string with some characters(can be none) deleted without changing the relative order of the remaining characters. (eg, “ace” is a subsequence of “abcde” while “aec” is not).
A common subsequence of two strings is a subsequence that is common to both strings.
If there is no common subsequence, return 0.

Example 1:
Input: text1 = “abcde”, text2 = “ace”
Output: 3    Explanation: The longest common subsequence is “ace” and its length is 3.

Example 2:
Input: text1 = “abc”, text2 = “abc”
Output: 3    Explanation: The longest common subsequence is “abc” and its length is 3.

Example 3:
Input: text1 = “abc”, text2 = “def”
Output: 0    Explanation: There is no such common subsequence, so the result is 0.

  LCS 重点就是想明白递推公式:

  • if text1[i] == text2[j],那么 lcs[i + 1][j + 1] = lcs[i][j] + 1
  • else,lcs[i + 1][j + 1] = max(lcs[i][j + 1], lcs[i + 1][j])

  这种二维矩阵 DP 问题,一般 DP 矩阵都会比数据多一个大小的位置,这样方便初始化,如下图,将所有初始化为0:

  AC 代码如下:

int longestCommonSubsequence(string text1, string text2) {
    const int len1 = text1.length(), len2 = text2.length();
    vector<vector<int>> lcs(len1 + 1, vector<int>(len2 + 1, 0));
    for(int i = 0; i < len1; ++i)
        for(int j = 0; j < len2; ++j) {
            if(text1[i] == text2[j])
                lcs[i + 1][j + 1] = lcs[i][j] + 1;
            else
                lcs[i + 1][j + 1] = max(lcs[i][j + 1], lcs[i + 1][j]);
        }
    return lcs[len1][len2];
}
二、Delete Operation for Two Strings

  像 LeetCode - 583. Delete Operation for Two Strings 这种题,用 LCS 很容易,算出两个字符串的最长公共子序列之后,用两个字符串的长度分别减这个公共子序列的长度,就是了:

int minDistance(string word1, string word2) {
	return word1.length() + word2.length() - 2 * longestCommonSubsequence(word1, word2);
}
三、Longest Palindromic Subsequence(LPS)

  像 LeetCode - 516. Longest Palindromic Subsequence,最长回文子序列的题也可以用 LCS 解决,就是将输入的字符串 s,翻转成 s’然后对 s 和 s’进行 LCS 的计算,当然 LPS 还有自己的 DP 方法,具体可以参考 https://blog.csdn.net/Bob__yuan/article/details/99693725

int longestPalindromeSubseq(string s) {
    string s_rev = s;
    reverse(s_rev.begin(), s_rev.end());
    return longestCommonSubsequence(s, s_rev);
}
四、Shortest Common Supersequence

  最短公共超序列,就是就是上边第二题的延伸,找出一个字符串 s,通过删除任意位置字符,可以得到 s1 和 s2 两个字符串,找出最短的 s。其实就是找出 lcs 的路径,不止是长度。所以 dp 的二维矩阵中存储的就不是当前 lcs 的长度了,而是当前的 lcs 字符串。然后用最终的 lcs 字符串,用过一个字符一个字符的比较,将需要添加的字符添加到的结果中即可。

string LCS(const string& s1, const string& s2) {
    const int len1 = s1.length(), len2 = s2.length();
    vector<vector<string>> lcs(len1 + 1, vector<string>(len2 + 1, ""));
    for(int i = 0; i < len1; ++i)
        for(int j = 0; j < len2; ++j) {
            if(s1[i] == s2[j])
                lcs[i + 1][j + 1] = lcs[i][j] + s1[i];
            else
                lcs[i+ 1][j + 1] = lcs[i + 1][j].length() > lcs[i][j + 1].length() ? lcs[i + 1][j] : lcs[i][j + 1];
        }
    return lcs[len1][len2];
}

string shortestCommonSupersequence(string str1, string str2) {
    string lcs = LCS(str1, str2), res;
    int i = 0, j = 0;
    for(const char& c : lcs) {
        while(str1[i] != c)
            res += str1[i++];
        while(str2[j] != c)
            res += str2[j++];
        res += c;
        ++i, ++j;
    }
    return res + str1.substr(i) + str2.substr(j);
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值