7. 3026.最大好子数组和(中等,学习)
思想
1.给你一个长度为 n
的数组 nums
和一个 正 整数 k
。
如果 nums
的一个子数组中,第一个元素和最后一个元素 差的绝对值恰好 为 k
,我们称这个子数组为 好 的。换句话说,如果子数组 nums[i..j]
满足 |nums[i] - nums[j]| == k
,那么它是一个好子数组。
请你返回 nums
中 好 子数组的 最大 和,如果没有好子数组,返回 0
。
2.此题|nums[i] - nums[j]| == k
,既可以枚举nums[j]
,寻找nums[j]+k
和nums[j]-k
,所以哈希表的键为nums[j]
.要让s[j+1]-s[i]
最大,此时s[j+1]
是固定的,所以要让s[i]
最小,所以哈希表的值为同一个nums[i]
下最小的s[i]
(不包括nums[i],所以先更新哈希表再更新s)(学习如何确定的思想)
代码
c++:
class Solution {
public:
long long maximumSubarraySum(vector<int>& nums, int k) {
int n = nums.size();
vector<long long> s(n + 1);
s[0] = 0;
for (int i = 0; i < n; ++i)
s[i + 1] = s[i] + nums[i];
long long res = LONG_MIN;
map<int, long long> mp; // nums[i]-相同nums[i]下s[i]的最小值
for (int j = 0; j < n; ++j) {
auto it1 = mp.find(nums[j] + k);
auto it2 = mp.find(nums[j] - k);
if (it1 != mp.end())
res = max(res, s[j + 1] - it1->second);
if (it2 != mp.end())
res = max(res, s[j + 1] - it2->second);
auto it3 = mp.find(nums[j]);
if (it3 == mp.end() || s[j] < it3->second)
mp[nums[j]] = s[j];
}
if (res == LONG_MIN)
return 0;
return res;
}
};
优化成一个变量,先更新哈希表再更新s
class Solution {
public:
long long maximumSubarraySum(vector<int>& nums, int k) {
int n = nums.size();
long long s = 0;
long long res = LONG_MIN;
map<int, long long>
mp; // nums[i]-相同nums[i]下s[i]的最小值(此时的nums[i]不包括nums[i],所以先更新哈希表再更新s)
for (auto& x : nums) {
auto it1 = mp.find(x + k);
auto it2 = mp.find(x - k);
if (it1 != mp.end())
res = max(res, s + x - it1->second);
if (it2 != mp.end())
res = max(res, s + x - it2->second);
auto it3 = mp.find(x);
// 先不包括nums[i]
if (it3 == mp.end() || s < it3->second)
mp[x] = s;
s += x;
}
if (res == LONG_MIN)
return 0;
return res;
}
};
8. 1477.找两个和为目标值且不重叠的子数组(中等,动态规划,之后再做)
1477. 找两个和为目标值且不重叠的子数组 - 力扣(LeetCode)
思想
代码
c++:
9. 1546.和为目标值且不重叠的非空子数组的最大数目(中等,细节处理)
1546. 和为目标值且不重叠的非空子数组的最大数目 - 力扣(LeetCode)
思想
1.给你一个数组 nums
和一个整数 target
。
请你返回 非空不重叠 子数组的最大数目,且每个子数组中数字和都为 target
。
2.思路没有问题,对于区间[l,r)
,要让s[r]-s[l]=target
,即s[l]=s[r]-target
,所以哈希表的键为s[r]
,因为要不重叠,所以采取贪心思想,记录前一个区间的右开 端点end,哈希表的值为闭 端点下标,此时的区间[it->second,i)
代码
c++:
class Solution {
public:
int maxNonOverlapping(vector<int>& nums, int target) {
int n = nums.size();
int s = 0;
map<int, int> mp; // s[i]-i
mp[0] = 0;
int cnt = 0;
int end = -1;
for (int i = 1; i <= n; ++i) {
s += nums[i - 1]; // s[i]
auto it = mp.find(s - target);
if (it != mp.end()) {
// [,end)与[it->second,i)不重叠
if (end <= it->second) {
++cnt;
end = i;
}
}
mp[s] = i;
}
return cnt;
}
};
10. 1124.表现良好的最长时间段(中等,单调栈待学习)
1124. 表现良好的最长时间段 - 力扣(LeetCode)
思想
代码
c++:
11. 3381.长度可被K整除的子数组的最大元素和(中等,学习)
3381. 长度可被 K 整除的子数组的最大元素和 - 力扣(LeetCode)
思想
1.给你一个整数数组 nums
和一个整数 k
。
返回 nums
中一个 非空子数组 的 最大 和,要求该子数组的长度可以 被 k
整除 。
2.区间[l,r)
,即(r-l)%k=0
,即r%k=l%k
,所以哈希表的键为j%k
,要让s[r]-s[l]
最大,所以哈希表的值为min(s[i])
,遍历前缀和数组,先更新答案,再更新哈希表,因为是取余,所以可以开长度为k的数组,初始值为LLONG_MAX/2
,防止减法溢出
代码
c++:
class Solution {
public:
long long maxSubarraySum(vector<int>& nums, int k) {
int n=nums.size();
vector<long long> s(n+1);
for(int i=0;i<n;++i) s[i+1]=s[i]+nums[i];
long long res=LLONG_MIN;
vector<long long> minS(k,LLONG_MAX/2);
// 遍历前缀和数组
for(int j=0;j<=n;++j){
int mod=j%k;
res=max(res,s[j]-minS[mod]);
minS[mod]=min(minS[mod],s[j]);
}
return res;
}
};
\*
map<int,long long> mp;
// 遍历前缀和数组
for (int j = 0; j <= n; ++j) {
int mod = j % k;
auto it=mp.find(mod);
if(it!=mp.end()){
res=max(res,s[j]-it->second);
}
if(it==mp.end() || s[j]<it->second) mp[mod]=s[j];
}
*\
单变量s优化:
class Solution {
public:
long long maxSubarraySum(vector<int>& nums, int k) {
int n = nums.size();
long long s = 0;
long long res = LLONG_MIN;
map<int, long long> mp; // 下标-值
mp[k - 1] = 0; // 前缀和第一个元素为0,下标为-1,取余k为k-1
for (int j = 0; j < n; ++j) {
s += nums[j];
int mod = j % k;
auto it = mp.find(mod);
if (it != mp.end()) {
res = max(res, s - it->second);
}
if (it == mp.end() || s < it->second)
mp[mod] = s;
}
return res;
}
};