Given a circular integer array nums
of length n
, return the maximum possible sum of a non-empty subarray of nums
.
A circular array means the end of the array connects to the beginning of the array. Formally, the next element of nums[i]
is nums[(i + 1) % n]
and the previous element of nums[i]
is nums[(i - 1 + n) % n]
.
A subarray may only include each element of the fixed buffer nums
at most once. Formally, for a subarray nums[i], nums[i + 1], ..., nums[j]
, there does not exist i <= k1
, k2 <= j
with k1 % n == k2 % n
.
Example 1:
Input: nums = [1,-2,3,-2] Output: 3 Explanation: Subarray [3] has maximum sum 3.
Example 2:
Input: nums = [5,-3,5] Output: 10 Explanation: Subarray [5,5] has maximum sum 5 + 5 = 10.
Example 3:
Input: nums = [-3,-2,-3] Output: -2 Explanation: Subarray [-2] has maximum sum -2.
Constraints:
n == nums.length
1 <= n <= 3 * 104
-3 * 104 <= nums[i] <= 3 * 104
This problem asks to find the maximum sum of a contiguous subarray within a circular array. A circular array means the last element connects to the first, allowing for subarrays that wrap around.
The solution cleverly handles this circularity by considering two cases:
Case 1: Maximum subarray sum without wrap-around. This is a standard maximum subarray sum problem, solvable using Kadane's Algorithm or similar dynamic programming approaches.
Case 2: Maximum subarray sum with wrap-around. This case is where the subarray spans the end and the beginning of the circular array. We can solve this by finding the minimum subarray sum and subtracting it from the total sum of the array. The remaining sum represents the maximum sum of the subarray that wraps around. The intuition is that the minimum subarray sum represents the portion to exclude to maximize the wrap-around sum.
The optimal solution efficiently combines these two cases in a single pass through the array.
Initialization:
pmi
: Minimum prefix sum (initialized to 0).pmx
: Maximum prefix sum (initialized to negative infinity).ans
: Maximum sum found so far (initialized to negative infinity).s
: Current prefix sum (initialized to 0).smi
: Minimum subarray sum (initialized to positive infinity).Iteration: Iterate through the nums
array:
s += x
(where x
is the current element).ans
: ans = max(ans, s - pmi)
. This finds the maximum subarray sum without wrap-around (Case 1).smi
: smi = min(smi, s - pmx)
. This tracks the minimum subarray sum for Case 2.pmi
: pmi = min(pmi, s)
.pmx
: pmx = max(pmx, s)
.Result: Return the maximum of ans
(Case 1) and s - smi
(Case 2). s - smi
represents the maximum sum with wrap-around.
def maxSubarraySumCircular(nums):
pmi, pmx = 0, float('-inf') # Initialize minimum and maximum prefix sums
ans, s, smi = float('-inf'), 0, float('inf') # Initialize answer, current sum, and minimum subarray sum
for x in nums:
s += x
ans = max(ans, s - pmi) # Update max sum (no wrap-around)
smi = min(smi, s - pmx) # Update min subarray sum (for wrap-around)
pmi = min(pmi, s) # Update min prefix sum
pmx = max(pmx, s) # Update max prefix sum
return max(ans, s - smi) # Return max of both cases
The implementations in other languages (Java, C++, Go, TypeScript) follow the same logic, with only syntax differences. The core algorithm remains the same for optimal efficiency.