题目理解:求任意子数组的最大和或者最小和。看了一眼数据规模,$1 \leq nums.length \leq 10^5 $。这个数组太长了,让我失去试试暴力解法($\mathcal{O}(n^2)$)的兴趣。这道题考的内容看起来像是双指针或者前缀和,当然也可能是其他解法,但是我暂时没有时间思考其他解法。
使用前缀和: 子数组的最大和或者最小和,只可能是当前的和,减去以前最小的前缀和或者以前最大的前缀和,包含了所有正负的可能。
static int x = [] () {ios::sync_with_stdio(false); cin.tie(0); return 0;} ();
class Solution {
public:
int maxAbsoluteSum(vector<int>& nums) {
vector<int> sums(nums.size());
partial_sum(nums.begin(), nums.end(), sums.begin());
int premin = 0, premax = 0;
int res = 0; // empty subarray has sum equals to 0
for (int i = 0, n = nums.size(); i < n; ++i) {
res = max({res, abs(sums[i] - premin), abs(sums[i] - premax)});
premax = max(premax, sums[i]);
premin = min(premin, sums[i]);
}
return res;
}
};
写完后发现,没有必要先计算出前缀和,只需要计算出当前的所有数的和,记住最大前缀和以及最小前缀和,就可以得出答案。上述代码可以简化,两遍遍历可以变为一遍,虽然没有减少计算量,但是代码会简洁一些。
static int x = [] () {ios::sync_with_stdio(false); cin.tie(0); return 0;} ();
class Solution {
public:
int maxAbsoluteSum(vector<int>& nums) {
int premin = 0, premax = 0, res = 0, sum = 0;
for (const int a: nums) {
sum += a;
res = max({res, abs(sum - premin), abs(sum - premax)});
premax = max(premax, sum);
premin = min(premin, sum);
}
return res;
}
};