Day47 | 动态规划 :线性DP 最长公共子序列&&最长公共子数组
本次题解参考自灵神的做法,大家也多多支持灵神的题解
动态规划学习:
1.思考回溯法(深度优先遍历)怎么写
注意要画树形结构图
2.转成记忆化搜索
看哪些地方是重复计算的,怎么用记忆化搜索给顶替掉这些重复计算
3.把记忆化搜索翻译成动态规划
基本就是1:1转换
文章目录
- [Day47 | 动态规划 :线性DP 最长公共子序列&&最长公共子数组](#Day47 | 动态规划 :线性DP 最长公共子序列&&最长公共子数组)
-
- 1143.最长公共子序列
-
- 思路分析(子问题):
- [1.回溯 DFS](#1.回溯 DFS)
- 2.记忆化搜索
- 3.1:1翻译为动态规划
- 718.最长重复子数组
- 1035.不相交的线
1143.最长公共子序列
[1143. 最长公共子序列 - 力扣(LeetCode)](https://leetcode.cn/problems/longest-common-subsequence/description/)\](https://leetcode.cn/problems/longest-increasing-subsequence/description/)
#### 思路分析(子问题):
设两个字符串分别是s和t
对应的最后一个字母分别是x和y
dfs(x,y)那就是s以x结尾,t以y结尾的两个字符串的最长公共子序列的长度了
那就有四种情况
1.选x这个字母也选y这个字母
2.不选x不选y
3.选x不选y
4.选y不选x
如果x==y,那肯定就是选x也选y,那肯定就是
dfs(x,y)=dfs(x-1,y-1)+1
如果说x!=y,那么就是剩下三种情况里面取一个最大值
```cpp
dfs(x,y)=max(dfs(x-1,y-1),dfs(x,y-1),dfs(x-1,y))
```
再仔细一看,其实
dfs(x,y-1),dfs(x-1,y)包含了dfs(x-1,y-1),所以不需要这个了
```cpp
dfs(x,y)=max(dfs(x,y-1),dfs(x-1,y))
```
不明白可以举例
dfs(x,y-1)=max(dfs(x-1,y-1),dfs(x,y-2))
递归边界:
只要x或者y小于0,那么就说明有一个字符串已经没有字母可以选择了,那么就到达了边界。
#### 1.回溯 DFS
**1.返回值和参数**
i是上面x字母的下标,j是y的下标
dfs(i,j)那就是s以x结尾,t以y结尾的两个字符串的最长公共子序列的长度了
```cpp
int dfs(int i,int j,string &s,string &t)
```
**2.终止条件**
只要有一个小于0就说明没有字符可以选了
```cpp
if(i<0||j<0)
return 0;
```
**3.本层逻辑**
相等就+1,不相等就三种选一种
```cpp
if(s[i]==t[j])
return dfs(i-1,j-1,s,t)+1;
else
return max(dfs(i-1,j,s,t),dfs(i,j-1,s,t));
```
**完整代码:**
当然,这是超时的
```cpp
class Solution {
public:
int dfs(int i,int j,string &s,string &t)
{
if(i<0||j<0)
return 0;
if(s[i]==t[j])
return dfs(i-1,j-1,s,t)+1;
else
return max(dfs(i-1,j,s,t),dfs(i,j-1,s,t));
}
int longestCommonSubsequence(string text1, string text2) {
return dfs(text1.size()-1,text2.size()-1,text1,text2);
}
};
```
```cpp
//lambda
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
function