Given a circular array C of integers represented by A
, find the maximum possible sum of a non-empty subarray of C.
Here, a circular array means the end of the array connects to the beginning of the array. (Formally, C[i] = A[i]
when 0 <= i < A.length
, and C[i+A.length] = C[i]
when i >= 0
.)
Also, a subarray may only include each element of the fixed buffer A
at most once. (Formally, for a subarray C[i], C[i+1], ..., C[j]
, there does not exist i <= k1, k2 <= j
with k1 % A.length = k2 % A.length
.)
Example 1:
Input: [1,-2,3,-2] Output: 3 Explanation: Subarray [3] has maximum sum 3
Example 2:
Input: [5,-3,5] Output: 10 Explanation: Subarray [5,5] has maximum sum 5 + 5 = 10
Example 3:
Input: [3,-1,2,-1] Output: 4 Explanation: Subarray [2,-1,3] has maximum sum 2 + (-1) + 3 = 4
Example 4:
Input: [3,-2,2,-3] Output: 3 Explanation: Subarray [3] and [3,-2,2] both have maximum sum 3
Example 5:
Input: [-2,-3,-1] Output: -1 Explanation: Subarray [-1] has maximum sum -1
Note:
-30000 <= A[i] <= 30000
1 <= A.length <= 30000
题目理解:
给定一个循环数组,即A[i]=A[i % length],找到这个循环数组的拥有最大和的子数组
解题思路:
循环数组的子数组一共有两种情况:
A[i],A[i+1],...A[j] j > i
A[j],A[j+1],...A[length]和A[0],A[1],...A[i] j > i
前一种情况直接用动态规划求解,dp[i]表示从A[0]开始,包含A[i]的子数组的最大和
dp[i] = max{dp[i-1] + A[i], A[i]}
然后在所有dp[i]中找到最大值即可
后一种情况只需要计算forward[i]和backward[i],forward[i]表示从A[0]开始并且包含A[0],最多到A[i]的最大数组和,backward[i]表示从A[length]开始并且包含A[length],往前最多到A[i]的子数组和,遍历所有的i,
res[i] = fordward[i] + backward[i+1]
然后在所有的res[i]中找到最大值即可
最后在两种情况中找到最大值
代码如下:
class Solution {
public int maxSubarraySumCircular(int[] A) {
int len = A.length;
int[] forward = new int[len];
for(int i = 0; i < len; i++) {
if(i == 0)
forward[i] = A[i];
else {
forward[i] = Math.max(A[i], A[i] + forward[i - 1]);
}
}
int[] backward = new int[len];
for(int i = len - 1; i > -1; i--) {
backward[i] = A[i];
if(i + 1 < len)
backward[i] += backward[i + 1];
}
for(int i = len - 2; i > -1; i--) {
backward[i] = Math.max(backward[i], backward[i + 1]);
}
for(int i = 1; i < len; i++) {
A[i] += A[i - 1];
}
int res = Integer.MIN_VALUE;
for(int i = 0; i < len; i++) {
int cur = forward[i];
int cir = A[i];
if(i + 1 < len && backward[i + 1] > 0)
cir += backward[i + 1];
cur = Math.max(cur, cir);
res = Math.max(res, cur);
}
return res;
}
}
对于后一种情况,有一种更加简单的方法,即如果A[j],A[j+1],...A[length]以及A[0],A[1],...A[i]的和最大,那么A[i],...A[j]一定是循环数组中和最小的子数组,因此只要用前面用到的动态规划算法计算一遍最小和数组,然后用整个数组的和减去即可