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
.
For example:
nums = [1,-2,3,-2]
should return 3
because the subarray [3]
has the maximum sum of 3.nums = [5,-3,5]
should return 10
because the subarray [5,5]
has the maximum sum of 10.nums = [-3,-2,-3]
should return -2
because the subarray [-2]
has the maximum sum of -2.Explain your approach, its time and space complexity, and handle edge cases such as all negative numbers. Provide a well-commented code solution.
Given a circular integer array nums
of length n
, the goal is to find the maximum possible sum of a non-empty subarray of nums
. A circular array means the end connects to the beginning. Each element can only be included once in any subarray.
A brute-force approach would involve iterating through all possible subarrays and computing their sums, keeping track of the maximum sum encountered. Since the array is circular, we need to consider subarrays that wrap around.
i
from 0
to n-1
.i
, iterate through all possible lengths len
from 1
to n
.i
with length len
, handling the circular nature of the array using the modulo operator.Code (Python):
def max_subarray_circular_naive(nums):
n = len(nums)
max_sum = float('-inf')
for i in range(n):
for length in range(1, n + 1):
current_sum = 0
for k in range(length):
current_sum += nums[(i + k) % n]
max_sum = max(max_sum, current_sum)
return max_sum
Time Complexity: O(n^2), due to the nested loops.
Space Complexity: O(1), as we only use a constant amount of extra space.
Kadane's Algorithm provides an efficient way to solve this problem.
The central idea is:
Algorithm:
max_circular = total_sum - min_kadane
.max_kadane
will be the largest number, and total_sum - min_kadane
will be zero. To handle this, if max_kadane
is negative and is the total sum, then return max_kadane
. If the max_kadane is equal to the total sum, it means we've considered the entire array, which invalidates the circularity aspect when we subtract min_kadane from the total sum. So we need to return max_kadane in that case.Code (Python):
def kadane(nums):
max_so_far = float('-inf')
current_max = 0
for x in nums:
current_max = max(x, current_max + x)
max_so_far = max(max_so_far, current_max)
return max_so_far
def min_kadane(nums):
min_so_far = float('inf')
current_min = 0
for x in nums:
current_min = min(x, current_min + x)
min_so_far = min(min_so_far, current_min)
return min_so_far
def max_subarray_circular(nums):
n = len(nums)
max_kadane_sum = kadane(nums)
min_kadane_sum = min_kadane(nums)
total_sum = sum(nums)
if max_kadane_sum < 0: # All numbers are negative, return max
return max_kadane_sum
max_circular = total_sum - min_kadane_sum
return max(max_kadane_sum, max_circular)
Time Complexity: O(n), as Kadane's algorithm takes O(n) time, and we perform it twice.
Space Complexity: O(1), as we only use a constant amount of extra space.