题目:最长公共子序列
解法一:二维数组
将两个字符串分别作为行 列以矩阵形式表示,同时将第一行、第一列填充为0,表示空字符串
之后从(1, 1)开始进行遍历(因为i和j不是从零开始,所以之后如果要使用对应下标的text1与text2,要将i、j减一),如果两个字符串的第i-1与j-1个字符相同,就在矩阵对应的位置填充“dp[i - 1][j - 1] + 1”,其中dp[i - 1][j - 1]代表着“text1的前 i 个字符与text2的前 j 个字符的最长公共子序列”
如果不同,就回滚到上一个字符,取text1的前 i-1 个字符与text2的前 j 个字符 与 text1的前 i 个字符与text2的前 j - 1 个字符中的最大值
1int longestCommonSubsequence(string text1, string text2)
2{
3 int res = 0;
4 int n1 = text1.size(), n2 = text2.size();
5 std::vector<std::vector<int>> dp(n1 + 1, std::vector<int>(n2 + 1, 0));
6
7 for(int i = 1; i <= n1; i++)
8 {
9 for(int j = 1; j <= n2; j++)
10 {
11 if(text1[i - 1] == text2[j - 1])
12 {
13 dp[i][j] = dp[i - 1][j - 1] + 1;
14 }
15 else
16 {
17 dp[i][j] = std::max(dp[i - 1][j], dp[i][j - 1]);
18 }
19 }
20 }
21 return dp[n1][n2];
22}
解法二:一维滚动数组
因为判断时只需要用到左,上,左上的三个值,所以 一维数组 + 一个额外变量 同样可以完成任务
dp数组第一个元素同样是零,进入循环后,先将当前元素进行保存,以供下一次循环使用(这里之所以使用 i + 1 而不是 i ,是因为第一位已经被定义为了零,所以要从第二位开始),之后根据字符是否相同更新当前位置的值——如果相同,则在上一个元素的基础上加一(代表总长度加一);如果不同,则取dp[i + 1](舍弃text1的当前字符)与dp[i](舍弃text2的当前字符)中的最大值
t[0] t[1] t[2]
s[0] ✓ ✓ ✓
s[1] ✓ ? ✓
s[2] ✓ ✓ ✓
总之就是记住,如果想要求 ?这个格子的值,当两个字符相同时,直接将左上角的值 + 1 赋过来;如果不同,就取左边与上方元素的更大者
1int longestCommonSubsequence(string text1, string text2)
2{
3 int n1 = text1.size(), n2 = text2.size();
4 std::vector<int> dp(n2 + 1);
5
6 for(auto c : text1)
7 {
8 for(int i = 0, pre = 0; i < n2; i++)
9 {
10 int temp = dp[i + 1];
11 dp[i + 1] = (c == text2[i]) ? pre + 1 : std::max(dp[i + 1], dp[i]);
12 pre = temp;
13 }
14 }
15 return dp[n2];
16}