
这个题和之前我们的718. 最长重复子数组 - 力扣(LeetCode)非常类似,唯一的区别在于这个题允许我们不连续,我们依然用动态规划的思路来做:
dp数组的含义:dp[i][j]表示长度为i和j的字符串text1和text2的最长公共子序列长度;递推公式:对于i和j,如果满足text1[i-1]==text2[j],我们就让dp[i][j]=dp[i-1][j-1]+1,为什么没有取max的过程了呢,因为我们的dp[i][j]一定是大于等于dp[i-1][j-1]的(整个递推公式只有加没有减的说法);如果不满足的话,我们的dp[i][j]就取dp[i-1][j]和dp[i][j-1]的最大值即可。初始化:显然初始化全为0即可;遍历顺序:正常遍历。
代码如下:
class Solution {
public:
int longestCommonSubsequence(string text1, string text2) {
int n1=text1.size(),n2=text2.size();
vector<vector<int>> dp(n1+1,vector<int>(n2+1,0));
for(int i=1;i<=n1;++i){
for(int j=1;j<=n2;++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]);
}
}
}
return dp[n1][n2];
}
};

这个题咋一看可能不理解什么意思,但其实画一画图就明白了:这就是在求我们的最长公共子序列。说实话,做题方法一模一样的,我就不再重复了。
class Solution {
public:
int maxUncrossedLines(vector<int>& nums1, vector<int>& nums2) {
int m=nums1.size(),n=nums2.size();
vector<vector<int>> dp(m+1,vector<int>(n+1,0));
for(int i=1;i<=m;++i){
for(int j=1;j<=n;++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]);
}
}
}
return dp[m][n];
}
};

不是哥们,怎么又是你。
写了无数遍了,可以用贪心算法和动态规划写,我们还是先都过一遍吧。
贪心:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int presum=0,cursum=nums[0];
for(int num:nums){
presum=max(presum+num,num);
cursum=max(cursum,presum);
}
return cursum;
}
};
动态规划的话,我们依然套路模板化来讨论:
dp数组的含义:dp[j]代表下标为j的数组nums的最大前缀和;递推公式:dp[j]=max(nums[j],dp[j-1]+nums[j]);初始化:dp[0]=nums[0];遍历顺序:正常遍历。
代码如下:
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n=nums.size();
vector<int> dp(n,0);
dp[0]=nums[0];
for(int i=1;i<n;++i){
dp[i]=max(dp[i-1]+nums[i],nums[i]);
}
return *max_element(dp.begin(), dp.end());
}
};

这个题算是编辑距离类型的经典题目,脑袋转得快的话其实也能想到:本质上这个题依然是在求我们的最大公共子序列,只是我们最后要判断我们的最大公共子序列的长度是否和我们的s的长度一样。除此之外还有一个最大的不同就是我们这个题是有比较的主体的,也就是我们在判断s是否为t的子序列,所以当我们发现两个字符串s[i-1]!=t[j-1]时,我们的dp[i][j]只能等于dp[i][j-1],也就是s的序号不能变而去修改t的序号。
代码如下:
class Solution {
public:
bool isSubsequence(string s, string t) {
int n1=s.size(),n2=t.size();
vector<vector<int>> dp(n1+1,vector<int>(n2+1,0));
for(int i=1;i<=n1;++i){
for(int j=1;j<=n2;++j){
if(s[i-1]==t[j-1])dp[i][j]=dp[i-1][j-1]+1;
else dp[i][j]=dp[i][j-1];
}
}
return dp[n1][n2]==n1;
}
};

8088

被折叠的 条评论
为什么被折叠?



