解题思路:动态规划
首先使用二维dp,令dp[i][j]表示s1的前i个字符构成的字符串和s2的前j个字符构成的字符串的最长公共子序列。
那么有状态转移方程:
当s1[i] == s2[j]时,dp[i + 1][j + 1] = dp[i][j] + 1;否则 dp[i + 1][j + 1] = max ( dp[i][j + 1], dp[i + 1][j] )
时间复杂度O(mn),空间复杂度O(mn)。
空间压缩,dp数组由二维压缩到一维
注意到动态转移方程中的 i+1只和 i 有关,因此可以将dp数组压缩到一维。
注意到题目要求的空间复杂度为 O(min(m, n)),我们强制令n >= m,如果 n < m 则交换m和n,交换s1和s2。
这样开的dp数组长度为m + 1最小,符合O(min(m, n))。
下面给出完整代码。
#include <iostream> #include <vector> using namespace std; int main() { int n, m; string s1, s2; cin >> n >> m; if(n < m) { cin >> s2 >> s1; swap(m, n); } else { cin >> s1 >> s2; } vector<int> dp(m + 1, 0); for(int i = 0; i < n; ++i) { int lastDp = 0; //表示上一项,即二维的dp[i][j],初始为dp[i][0] = 0 for(int j = 0; j < m; ++j) { int tmp = dp[j + 1]; //临时记录当前项,即二维的dp[i][j+1] if(s1[i] == s2[j]) { dp[j + 1] = lastDp + 1; //即dp[i+1][j+1] = dp[i][j] + 1 } else { dp[j + 1] = max(dp[j + 1], dp[j]); //即dp[i+1][j+1]=max(dp[i][j+1], dp[i+1][j]) } lastDp = tmp; //更新上一项为之前临时记录的 } } cout << dp[m]; } // 64 位输出请用 printf("%lld")