目录
最大子数组和
dp表示当前元素结束的最大连续子数组和
参考代码
class Solution {
public:
int maxSubArray(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n);
dp[0] = nums[0];
int ret = dp[0];
for(int i = 1; i < n; i++)
{
dp[i] = max(dp[i - 1] + nums[i], nums[i]);
ret = max(ret, dp[i]);
}
return ret;
}
};
环形子数组的最大和
细节:sum == g[i] 时返回f[0] 或sum 都可以,这时候全是负数f[i] 一定 >= g[i]
不相等情况下sum - g[i], 相等时为0(但其实这时候是最小值) ,所以要判断sum 与 g[i]是否相等
参考代码
class Solution {
public:
int maxSubarraySumCircular(vector<int>& nums) {
int n = nums.size();
vector<int> f(n), g(n);
f[0] = g[0] = nums[0];
int sum = 0;
for(auto e : nums)
sum += e;
int ret = f[0];
for(int i = 1; i < n; i++)
{
f[i] = max(f[i - 1] + nums[i], nums[i]);
g[i] = min(g[i - 1] + nums[i], nums[i]);
ret = max(ret, max(f[i], sum == g[i] ? f[0] : sum - g[i]));
}
return ret;
}
};
乘积最大子数组
乘法 : 负数 * 负数也是正数
f:表示到 i 位置结束的最大子串
g:表示到 i 位置结束的最小子串
一共也就三种情况放一起比较,
错误:min和max写错
参考代码
class Solution {
public:
int maxProduct(vector<int>& nums) {//环形呢?
int n = nums.size();
vector<int> f(n), g(n);
f[0] = g[0] = nums[0];
int ret = f[0];
for(int i = 1; i < n; i++)
{
f[i] = max(f[i - 1] * nums[i], max(g[i - 1] * nums[i], nums[i]));
// g[i] = min(f[i - 1] * nums[i], max(g[i - 1] * nums[i], nums[i]));
g[i] = min(f[i - 1] * nums[i], min(g[i - 1] * nums[i], nums[i]));
ret = max(ret, f[i]);
}
return ret;
}
};
乘积为正数的最长子数组长度
初始化:讨论第一个值正负来初始化f[0], g[0]
细节概念:在nums[i] > 0 的时候g(i) 不一定是g[i - 1] + 1,如果g[i - 1] == 0,那么这样操作里面就是一个正数;在nums[i] < 0 的时候,如果g[i - 1] == 0, 那么f[i]就成一个负数
错误:符号优先级g[i] = (g[i - 1] == 0 ? -1 : g[i - 1]) + 1;开始是想着-1 和 g[i - 1] , -1 是为了和掉+1,变成0,不如这么写:g[i] = g[i - 1] == 0 ? 0 : g[i - 1] + 1;
参考代码
class Solution {
public:
int getMaxLen(vector<int>& nums) {
int n = nums.size();
vector<int> f(n), g(n);
if(nums[0] > 0) f[0] = 1;
else if(nums[0] < 0) g[0] = 1;
int ret = f[0];
for(int i = 1; i < n; i++)
{
if(nums[i] > 0)
{
f[i] = f[i - 1] + 1;
g[i] = (g[i - 1] == 0 ? -1 : g[i - 1]) + 1;//符号优先级
}
else if(nums[i] < 0)
{
f[i] = (g[i - 1] == 0 ? -1 : g[i - 1]) + 1;
g[i] = f[i - 1] + 1;
}
ret = max(ret, f[i]);
}
return ret;
}
};
等差数列划分
没有说是不同的等差数列
dp指的是已改位置为结尾的等差数列个数
dp[i] += dp[i - 1] + 1这里的 + 1 比如说i = 5, dp[4] 是转换过来是1 2 3 4 5; 2 3 4 5;这里的 + 1 是3 4 5;能延续的有dp[i - 1]个,新增一个
参考代码
class Solution {
public:
int numberOfArithmeticSlices(vector<int>& nums) {
int n = nums.size();
vector<int> dp(n);
int ret = 0;
for(int i = 2; i < n; i++)
if(nums[i] - nums[i - 1] == nums[i - 1] - nums[i - 2])
dp[i] += dp[i - 1] + 1, ret += dp[i]; //这个1表示的是哪个区间
return ret;
}
};
最长湍流子数组
初始化:示例3看出,只有一个元素时,湍流子数组长度为1,那就初始化为1;
dp表:f表示上升(当前元素 > 上一个元素) 时最大湍流子数组;g类似
参考代码
class Solution {
public:
int maxTurbulenceSize(vector<int>& arr) {
int n = arr.size();
vector<int> f(n, 1), g(n, 1);
int ret = 1;
for(int i = 1; i < n; i++)
{
if(arr[i] > arr[i - 1]) f[i] = g[i - 1] + 1;
else if(arr[i] < arr[i - 1]) g[i] = f[i - 1] + 1;
ret = max(ret, max(f[i], g[i]));
}
return ret;
}
};
单词拆分
初始化:第一个字符
注意语法:count函数里面不能传char类型,所以不能传s[0],因为hash的模版参数是string
比方说 i 在这个位置是true 说明 [0, i] 这个区间可以由wordDict里面的字符串拼接成
j的扫描区间是[1, i] 从左从右都可以;
解释 j 不能从之前的true开始扫描,样例:
细节:因为 j 是从 1 开始的,那么就少了[0, i]这个区间的判断,j 不从 0 开始是怕越界,且dp[j - 1]起到连接的操作(dp: 到i位置 (即区间[0, i]) 能不能被拼接)
参考代码
class Solution {
public:
bool wordBreak(string s, vector<string>& wordDict) {
unordered_set<string> hash;
for(auto e : wordDict)
hash.insert(e);
int n = s.size();
vector<bool> dp(n);
// if(hash.count(s.substr(0, 1))) dp[0] = true;
dp[0] = hash.count(s.substr(0, 1)) == 1 ? true : false;
for(int i = 1; i < n; i++)
{
if(hash.count(s.substr(0, i + 1)))
{
dp[i] = true;
continue;
}
for(int j = 1; j <= i; j++)
{
if(dp[j - 1] && hash.count(s.substr(j, i - j + 1)))
{
dp[i] = true;
break;
}
}
}
return dp[n - 1];
}
};
环绕字符串中唯一的子字符串
dp[i] = dp[i - 1] + 1;这里的 + 1加的是自己,自己就是那个新的
dp[i] 就是当前元素的符合条件的个数
初始化:i从 1 开始dp[0] 为1, arr[s[0] - ' a '] ++;
参考代码1
class Solution {
public:
int findSubstringInWraproundString(string s) {
int n = s.size();
vector<int> dp(n, 1), arr(26);
arr[s[0] - 'a']++;
for(int i = 1; i < n; i++)
{
if(s[i - 1] + 1 == s[i] || s[i - 1] == 'z' && s[i] == 'a')
dp[i] = dp[i - 1] + 1;
arr[s[i] - 'a'] = max(arr[s[i] - 'a'], dp[i]);
}
int ret = 0;
for(auto e : arr)
{
ret += e;
}
return ret;
}
};
也可以不减 'a' 开128 个就行
参考代码2
class Solution {
public:
int findSubstringInWraproundString(string s) {
int n = s.size();
vector<int> dp(n, 1), arr(128);
arr[s[0]]++;
for(int i = 1; i < n; i++)
{
if(s[i - 1] + 1 == s[i] || s[i - 1] == 'z' && s[i] == 'a')
dp[i] = dp[i - 1] + 1;
arr[s[i]] = max(arr[s[i]], dp[i]);
}
int ret = 0;
for(auto e : arr)
{
ret += e;
}
return ret;
}
};