53. 最大子数组和
这题只需要明白一点,如果i位置之前的连续子数组的和小于0,那么如果加上这个小于0的和只会让nums[i]的值变得更小。所以这个时候我们要舍弃之前的连续子数组,重新开始,也就是将i位置之前的连续子数组的和置为0
class Solution {
public:
//sum表示子数组的和,ans表示答案
int sum=0,ans=-10000;
int maxSubArray(vector<int>& nums) {
for(int i=0;i<nums.size();i++)
{
if(sum<0)
sum=0;
sum+=nums[i];
ans=max(ans,sum);
}
return ans;
}
};
392. 判断子序列
方法一:暴力解法
直接遍历一遍t
class Solution {
public:
bool isSubsequence(string s, string t) {
if(s.size()==0)
{
return true;
}
if( t.size()==0)
{
if(s.size()==0)
{
return true;
}
else
{
return false;
}
}
int i=0;
for(char c:t)
{
if(c==s[i])
{
i++;
}
if(i==s.size())
{
return true;
}
}
return false;
}
};
方法二:动态规划
其实就是求字符串s和t的最长公共子序列,如果这个最长公共子序列的长度等于s的长度,那么就说明s就是t的子序列。
class Solution {
public:
bool isSubsequence(string s, string t) {
vector<vector<int>> dp(s.size()+1,vector<int>(t.size()+1,0));
for(int i=1;i<=s.size();i++)
{
for(int j=1;j<=t.size();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])
//因为dp[i-1][j]一定没有dp[i][j-1]大
dp[i][j]=dp[i][j-1];
}
}
if(dp[s.size()][t.size()]==s.size())
return true;
return false;
}
};
115. 不同的子序列
像这类有两个字符串,求子序列、子数组或者子序列个数子数组个数一般都分成两种情况去讨论状态方程。一种是两字符相等,一种是两字符不相等。
以s=abab t=ab举例,dp[i][j]表示s中0到i-1字符串中有多少个
1.两字符相等
当i=3,j=1时,dp[i][j]就等于不用当前字符时s里面有多少个t,用当前字符新增了多少个t。得到递推公式dp[i][j]=dp[i-1][j]+dp[i-1][j-1]
2.两字符不相等
dp[i][j]就等于不用当前字符时s里面有多少个t
class Solution {
public:
int numDistinct(string s, string t) {
vector<vector<unsigned long long>> dp(s.size()+1,vector<unsigned long long>(t.size()+1,0));
for(int i=0;i<=s.size();i++)
{
dp[i][0]=1;
}
for(int i=1;i<=s.size();i++)
{
for(int j=1;j<=t.size();j++)
{
if(s[i-1]==t[j-1])
//如果相等,次数就等于之前就拥有的次数加上新产生的次数
dp[i][j]=dp[i-1][j]+dp[i-1][j-1];
else
dp[i][j]=dp[i-1][j];
}
}
return dp[s.size()][t.size()];
}
};
总结
子数组、子序列问题都是分两种情况。当前字符相等、当前字符不相等。