赞
踩
LCS 是很经典的 DP 问题,很多公司面试都会考,也有很多问题可以用 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 重点就是想明白递推公式:
这种二维矩阵 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];
}
像 LeetCode - 583. Delete Operation for Two Strings 这种题,用 LCS 很容易,算出两个字符串的最长公共子序列之后,用两个字符串的长度分别减这个公共子序列的长度,就是了:
int minDistance(string word1, string word2) {
return word1.length() + word2.length() - 2 * longestCommonSubsequence(word1, word2);
}
像 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);
}
最短公共超序列,就是就是上边第二题的延伸,找出一个字符串 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); }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。