文章目录
总结
(一)718连续的dp定义和递推:
定义dp[i][j]为以下标 i-1 为结尾的A,和以下标 j-1 为结尾的B,最长重复子数组长度
if(nums1[i-1]==nums2[j-1]) dp[i][j]=dp[i-1][j-1]+1;
//if(nums1[i]!=nums2[j]) dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
(二)1143不连续的dp定义和递推:
定义dp[i][j]为,[0, i-1] 范围内的A,和[0, j-1] 范围内的的B,最长重复子序列长度
if(text1[i-1]==text2[j-1]) dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
(三)区别:
1.dp[i][j]定义一个是必须以i,j结尾,一个是范围
2.递推一个只能由dp[i-1][j-1]推出,一个还有dp[i-1][j]和dp[i][j-1]
3.并且由于dp定义不同dp数组大小自然也不同,一个是len+1,一个是len
(四)不连续->[0,i-1]范围->两个状态来源->答案为dp[len1][len2]; 连续->以i-1结尾->一个状态来源->答案为所有dp数组的最大值;
Leetcode718(要求公共子序列连续)
1.问题描述
2.解决方案
递推很重要!!!!
这道题的递推只有上面那行,因为dp[i][j]的状态只能由dp[i-1][j-1]推导出,由于定义是以i,j为结尾的最长,而不是[0,i][0,j]范围内的最长
if(nums1[i]==nums2[j]) dp[i][j]=dp[i-1][j-1]+1;
//if(nums1[i]!=nums2[j]) dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
解法一:自己的dp定义,二维数组
自己的dp定义:定义dp[i][j]为以下标 i 为结尾的A,和以下标 j 为结尾的B,最长重复子数组长度
1.这样的定义难点在于初始化,相对复杂,需要对第0行,第0列进行初始化
2.并且需要用flag标记第0行,第0列是否有1,有1,在循环前就得记录
class Solution {
public:
int findLength(vector<int>& nums1, vector<int>& nums2) {
//1.
int len1=nums1.size();
int len2=nums2.size();
//2.
vector<vector<int> > dp(len1,vector<int>(len2,0));
bool flag= false;
for(int i=0;i<len1;i++){
if(nums1[i]==nums2[0]) {dp[i][0]=1; flag=true;}
}
for(int i=0;i<len2;i++){
if(nums2[i]==nums1[0]) {dp[0][i]=1; flag=true;}
}
//3.
int ans=0;
if(flag== true) ans=1;
for(int i=1;i<len1;i++){
for(int j=1;j<len2;j++){
if(nums1[i]==nums2[j]) dp[i][j]=dp[i-1][j-1]+1;
//if(nums1[i]!=nums2[j]) dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
ans=max(ans,dp[i][j]);
}
}
//4.
return ans;
}
};
解法二:代码sxl实现合理的dp定义,二维数组
代码sxl合理的dp定义:定义dp[i][j]为以下标 i-1 为结尾的A,和以下标 j-1 为结尾的B,最长重复子数组长度
1.初始化很简单,根绝定义和递推需要全部为0
2.递推一样,只有一种状态来源
class Solution1 {
public:
int findLength(vector<int>& nums1, vector<int>& nums2) {
//1.
int len1=nums1.size();
int len2=nums2.size();
//2.
vector<vector<int> > dp(len1+1,vector<int>(len2+1,0));
//bool flag= false;
//for(int i=0;i<len1;i++){
// if(nums1[i]==nums2[0]) {dp[i][0]=1; flag=true;}
//}
//for(int i=0;i<len2;i++){
// if(nums2[i]==nums1[0]) {dp[0][i]=1; flag=true;}
//}
//3.
int ans=0;
//if(flag== true) ans=1;
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
if(nums1[i-1]==nums2[j-1]) dp[i][j]=dp[i-1][j-1]+1;
//if(nums1[i]==nums2[j]) dp[i][j]=dp[i-1][j-1]+1;
//if(nums1[i]!=nums2[j]) dp[i][j]=max(dp[i][j-1],dp[i-1][j]);
ans=max(ans,dp[i][j]);
}
}
//4.
return ans;
}
};
解法三:代码sxl实现合理的dp定义,二维数组滚动数组
1.内层只用上一层的数据,不用新更新的数据,所以内层倒序遍历
2.并且如果不发生状态转移要归零,方便下一层使用
class Solution {
public:
int findLength(vector<int>& nums1, vector<int>& nums2) {
//1.
int len1=nums1.size();
int len2=nums2.size();
//2.
vector<int> dp(len2+1,0);
//3.
int ans=0;
for(int i=1;i<=len1;i++){
for(int j=len2;j>=1;j--){
if(nums1[i-1]==nums2[j-1]) dp[j]=dp[j-1]+1;
else dp[j]=0;
ans=max(ans,dp[j]);
}
}
//4.
return ans;
}
};
Leetcode1143(要求公共子序列不一定连续)
1.问题描述
2.解决方案
a.本题和718除了要求子序列不连续其他的都一样
b.dp的定义由以i-1 j-1 结尾改为 [0,i-1][0,j-1] 范围内的公共子序列
c.定义不同递推也增加一条dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
d.定义不是范围[0,i] [0,j],而是范围[0,i-1] [0,j-1],所以全部初始化为0就好
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
//1.
int len1=text1.size();
int len2=text2.size();
if(len1==0||len2==0) return 0;
//2.
vector<vector<int> > dp(len1+1,vector<int>(len2+1,0));
//3.
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
if(text1[i-1]==text2[j-1]) dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
//4.
return dp[len1][len2];
}
};
Leetcode1035(要求公共子序列不一定连续,和1143一摸一样)
1.问题描述
2.解决方案
这道题目首先你得把题目分析清楚了,要连线那就是要求求完全相同的子序列,连线不能相交那就保持原来的顺序,那这么一分析发现和1143是一摸一样的求不连续最长子序列长度,所以代码一摸一样不用动!
class Solution {
public:
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
//1.
int len1=nums1.size();
int len2=nums2.size();
//2.
vector<vector<int> > dp(len1+1,vector<int>(len2+1,0));
//3.
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
if(nums1[i-1]==nums2[j-1]) dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
//4.
return dp[len1][len2];
}
};
Leetcode392(要求公共子序列不一定连续,和1143一摸一样)
1.问题描述
2.解决方案
a.本题完全符合上面总结的不连续的套路,dp定义是范围,状态两个来源,答案是dp[len1][len2]
b.本题稍微一转化就发现和1143是一模一样的,就是求不连续公共子序列最长长度,只不过这道题,最后只需要判断不连续公共子序列最长长度是不是等于s.size(),等于那就是子序列不等于那就不是,其他的一摸一样,包括dp定义,递推,初始化等等
class Solution {
public:
bool isSubsequence(string s, string t) {
//1.
int len1=s.size();
int len2=t.size();
//2.
vector<vector<int> > dp(len1+1,vector<int>(len2+1,0));
//3.
for(int i=1;i<=len1;i++){
for(int j=1;j<=len2;j++){
if(s[i-1]==t[j-1]) dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
}
}
//4.
if(dp[len1][len2]==len1) return true;
else return false;
}
};