leetcode 1749. 任意子数组和的绝对值的最大值
没做出来🤡
法一:动态规划
class Solution {
public:
int maxAbsoluteSum(vector<int>& nums) {
int res = 0;
// 初始化以当前元素为结尾的子数组的最大和f_max为0
int f_max = 0;
// 初始化以当前元素为结尾的子数组的最小和f_min为0
// 注意:这里用最小和而不是负的最大和,是为了同时处理正负数情况,简化逻辑
int f_min = 0;
for(int &n : nums){
// 更新f_max:如果前面的子数组和大于等于0,则加上当前元素n可能使和更大;
// 否则,从当前元素n开始重新计算子数组和(即f_max = n),因为加上前面的负数只会使和变小
f_max = max(f_max, 0) + n;
// 更新f_min:逻辑与f_max类似,但用于找最小和。
// 如果前面的子数组和小于等于0,则加上当前元素n可能使和更小;
// 否则,从当前元素n的相反数开始重新计算子数组和(即f_min = -n的相反数,但这里直接写为n加上之前的最小负和),
// 因为加上前面的正数只会使和变大,而我们需要找最小和,所以这里通过记录最小负和来间接找到最小和
f_min = min(f_min, 0) + n;
// 更新结果res:比较当前的最大绝对和(即f_max的绝对值与-f_min的绝对值中较大的一个)与之前的最大绝对和res
// -f_min是因为f_min记录的是最小和,而我们需要的是最大绝对和,所以取反来比较
res = max(res, max(f_max, -f_min));
}
// 返回遍历结束后找到的最大绝对和
return res;
}
};
法二:前缀和
class Solution {
public:
//由于子数组和等于两个前缀和的差,那么取前缀和中的最大值与最小值,它俩的差就是答案。
//如果最大值在最小值右边,那么算的是最大子数组和。如果最大值在最小值左边,那么算的是最小子数组和的绝对值(相反数).
int maxAbsoluteSum(vector<int>& nums) {
int sum = 0;// 初始化当前的前缀和为0
int minSum = 0;// 初始化最小前缀和为0,用于记录遍历过程中遇到的最小前缀和
int maxSum = 0;// 初始化最大前缀和为0,用于记录遍历过程中遇到的最大前缀和
for(int &n : nums){
sum += n; //更新当前的前缀和,即当前元素n加上之前的前缀和
minSum = min(minSum, sum);// 更新最小前缀和,如果当前前缀和小于已知的最小前缀和,则更新
maxSum = max(maxSum, sum);// 更新最大前缀和,如果当前前缀和大于已知的最大前缀和,则更新
}
// 返回最大前缀和与最小前缀和的差,这个差值即为子数组和的最大绝对值
// 因为无论最大前缀和在前还是在后,与最小前缀和的差值都能反映出子数组和的最大绝对值
// 如果最大前缀和在最小前缀和的右边,那么差值为正,表示最大子数组和;
// 如果最大前缀和在最小前缀和的左边,那么差值为负,但由于我们要求的是绝对值,所以结果仍然正确。
return maxSum - minSum;
}
};