Maximum Sum Circular Subarray LT918

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

 Idea 1. Similar to Maximum Subarray LT53, the difference is the circular array part, the subarray could be the tail(A[j..n-1]) plus the head(A[0..i]) (i+1 < j), if the subarray of tail + head is the maximum, the subarray in the middle is A[i+1, j-1] has the minSum, once the minSum is found, the maxSum is Sum - minSum, except maxSum = 0 if all values in the array are negative, as minSum == Sum.

Note. negative arrays

Time complexity: O(n)

Space complexity: O(1)

 1 class Solution {
 2     public int maxSubarraySumCircular(int[] A) {
 3         int maxSoFar = 0;
 4         int minSoFar = 0;
 5         
 6         int sum = 0;
 7         int minSum = Integer.MAX_VALUE;
 8         int maxSum = Integer.MIN_VALUE;
 9         
10         for(int a: A) {
11             maxSoFar = a + Math.max(maxSoFar, 0);
12             maxSum = Math.max(maxSum, maxSoFar);
13             
14             minSoFar = a + Math.min(minSoFar, 0);
15             minSum = Math.min(minSum, minSoFar);
16             
17             sum += a;
18         }
19         
20         if(sum == minSum) {
21             return maxSum;
22         }
23         return Math.max(maxSum, sum - minSum);
24     }
25 }

Idea 2. 另外一种方法求2个intervals (head + tail)组成的,如果直接从左到右+从右到左的和,可能中间有重合,固定一边,求另外一边的和的最大值,保证j >= i+2.

Time complexity: O(n)

Space complexity: O(n)

 1 class Solution {
 2     public int maxSubarraySumCircular(int[] A) {
 3         int curr = 0;
 4         int n = A.length;
 5         int maxSum = Integer.MIN_VALUE;
 6         
 7         for(int a: A) {
 8             curr = a + Math.max(curr, 0);
 9             maxSum = Math.max(maxSum, curr);
10         }
11         
12         int[] rightMaxSum = new int[n];
13         rightMaxSum[n-1] = A[n-1];
14         curr = A[n-1];
15         for(int i = n-2; i >= 0; --i) {
16             curr += A[i];
17             rightMaxSum[i] = Math.max(curr, rightMaxSum[i+1]);
18         }
19         
20         curr = 0;
21         int result = maxSum;
22         for(int i = 0; i+2 < n; ++i) {
23             curr += A[i];
24             result = Math.max(result, curr + rightMaxSum[i+2]);
25         }
26         
27         return result;
28     }
29 }

Idea 3. Similar to sliding window minValue, build a min deque for prefix sum, for each prefix sum, find the minimum of previous prefixSum so that the subarray sum ending here is the maximu, since it's circular array, j - i <= n, remove the invalid previous index. Note: store the index

Time complexity: O(n)

Space complexity: O(n)

 1 class Solution {
 2     public int maxSubarraySumCircular(int[] A) {
 3         Deque<Integer> minPrefix = new LinkedList<>();
 4         minPrefix.addLast(0);
 5         
 6         int n = A.length;
 7         
 8         int[] prefix = new int[2*n + 1];
 9         for(int i = 0; i < 2*n; ++i) {
10             prefix[i+1] = prefix[i] + A[i%n];
11         }
12         int result = Integer.MIN_VALUE;
13         for(int i = 1; i <= 2*n; ++i) {
14             
15             if(i - minPrefix.getFirst() > n) {
16                 minPrefix.removeFirst();
17             }
18             
19             result = Math.max(result, prefix[i] - prefix[minPrefix.getFirst()]);
20             
21             while(!minPrefix.isEmpty() && prefix[minPrefix.getLast()] >prefix[i]) {
22                 minPrefix.removeLast();
23             }
24             minPrefix.add(i);
25             
26         }
27         
28         return result;
29     }
30 }

Note:

  1. -30000 <= A[i] <= 30000
  2. 1 <= A.length <= 30000

猜你喜欢

转载自www.cnblogs.com/taste-it-own-it-love-it/p/10760211.html
今日推荐