class Solution {
public int maxSubArray(int[] nums) {
int pre = 0, maxAns = nums[0];
for (int x : nums) {
pre = Math.max(pre + x, x);
maxAns = Math.max(maxAns, pre);
}
return maxAns;
}
}
class Solution {
public int maxSubarraySumCircular(int[] nums) {
int n = nums.length;
int[] leftMax = new int[n];
// 对坐标为 0 处的元素单独处理,避免考虑子数组为空的情况
leftMax[0] = nums[0];
int leftSum = nums[0];
int pre = nums[0];
int res = nums[0];
for (int i = 1; i < n; i++) {
pre = Math.max(pre + nums[i], nums[i]);
res = Math.max(res, pre);
leftSum += nums[i];
leftMax[i] = Math.max(leftMax[i - 1], leftSum);
}
// 从右到左枚举后缀,固定后缀,选择最大前缀
int rightSum = 0;
for (int i = n - 1; i > 0; i--) {
rightSum += nums[i];
res = Math.max(res, rightSum + leftMax[i - 1]);
}
return res;
}
}
class Solution {
public int maxSubarraySumCircular(int[] nums) {
int n = nums.length;
int preMax = nums[0], maxRes = nums[0];
int preMin = nums[0], minRes = nums[0];
int sum = nums[0];
for (int i = 1; i < n; i++) {
preMax = Math.max(preMax + nums[i], nums[i]);
maxRes = Math.max(maxRes, preMax);
preMin = Math.min(preMin + nums[i], nums[i]);
minRes = Math.min(minRes, preMin);
sum += nums[i];
}
if (maxRes < 0) {
return maxRes;
} else {
return Math.max(maxRes, sum - minRes);
}
}
}
class Solution {
// 单调队列,队列中存放的是前缀和,从fist到last是递增的。
public int maxSubarraySumCircular(int[] nums) {
int length = nums.length;
int count = length << 1;
Deque<int[]> queue = new LinkedList<>();
int preSum = nums[0];// 前缀和
int max = nums[0];// 返回的结果
queue.offerLast(new int[]{0, preSum});
for (int i = 1; i < count; i++) {
// 队列中最老元素的下标到当前距离不能大于数组长度length。
if (!queue.isEmpty() && i - queue.peekFirst()[0] > length)
queue.pollFirst();
preSum += nums[i % length];// 累加前缀和。
// 计算最大和,queue中元素是单调递增的,直接减去first即可。
max = Math.max(max, preSum - queue.peekFirst()[1]);
// 维护递增队列,把当前值添加之前,需要把前面比preSum大或相等的都要移除。
while (!queue.isEmpty() && queue.peekLast()[1] >= preSum)
queue.pollLast();
queue.offerLast(new int[]{i, preSum});// 添加到队列中。
}
return max;
}
}