第23天。
今天的题目是 Longest Common Subsequence :
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:
1Input: text1 = "abcde", text2 = "ace"2Output: 33Explanation: The longest common subsequence is "ace" and its length is 3.
Example 2:
1Input: text1 = "abc", text2 = "abc"2Output: 33Explanation: The longest common subsequence is "abc" and its length is 3.
Example 3:
1Input: text1 = "abc", text2 = "def"2Output: 03Explanation: There is no such common subsequence, so the result is 0.
Constraints:
1 <= text1.length <= 1000
1 <= text2.length <= 1000
- The input strings consist of lowercase English characters only.
这是一道比较经典的动态规划问题吧,它的动规方程为: $$ \begin{aligned} LCS(i,j) = \left{ \begin{array}{rcl}
& LCS[i-1, j-1] + 1 & ,{s1[i] = s2[j]} \ & max(LCS[i, j-1], LCS[i-1, j]) & ,{s1[i] \neq s2[j]}
\end{array} \right. \end{aligned} $$ 根据动规方程我们可以写出如下代码:
1int longestCommonSubsequence(string text1, string text2) {2 vector<vector<int>> dp(text1.size() + 1, vector<int>(text2.size() + 1, 0));3 for(int i = 1;i < dp.size(); i++) {4 for(int j = 1;j < dp[0].size(); j++) {5 if (text1[i-1] == text2[j-1]) {6 dp[i][j] = dp[i-1][j-1] + 1;7 } else {8 dp[i][j] = max(dp[i-1][j], dp[i][j-1]);9 }10 }11 }12 return dp[text1.size()][text2.size()];13}
这里的空间复杂度可以继续进行优化,因为LCS[i,j]
只与当前行和上一行有关系,所以可以优化成两个数组来做:
1int longestCommonSubsequence(string text1, string text2) {2
3 int n = text1.size() + 1, m = text2.size() + 1;4 vector<int> dp1(m, 0);5 vector<int> dp2(m);6
7 for(int i = 1;i < n; i++) {8 dp1[0] = 0;9 for(int j = 1;j < m; j++) {10 if (text1[i-1] == text2[j-1]) {11 dp2[j] = dp1[j-1] + 1;12 } else {13 dp2[j] = max(dp1[j], dp2[j-1]);14 }15 }4 collapsed lines
16 swap(dp1, dp2);17 }18 return dp1[m-1];19}
再进一步的话,我们可以发现dp[i][j]
只与 dp[i-1][j-1]
,dp[i-1][j]
,dp[i][j-1]
相关,如果我们只用一个数组的话,dp[i][j]
与dp[i-1][j]
其实存在同一个位置,而dp[i][j-1]
是在同一行,所以我们只需要维护一个prev
变量来保存dp[i-1][j-1]
的值即可:
1int longestCommonSubsequence(string text1, string text2) {2 int n = text1.size(), m = text2.size() + 1;3 vector<int> dp(m, 0);4
5 for(int i = 0;i < n; i++) {6 int prev = 0;7 for(int j = 1;j < m; j++) {8 int temp = prev;9 prev = dp[j];10 dp[j] = (text1[i] == text2[j-1]) ? (temp + 1) : (max(dp[j], dp[j-1]));11 }12 }13 return dp[m-1];14}