最大子数组是连续的若干数组元素,若其和是最大的,那么这个子数组就称为该数组的最大子数组,它是很多问题的抽象,比如购买股票,把相邻两天的股价之差作为数组元素,求在连续的某个时间段内买入股票的最佳时间和卖出股票的最佳时间就可以抽象为计算最大子数组的问题 [^3]。
求解最大子数组问题有分治法和贪心算法(这里结合动态规划思想的变种贪心算法,即Kadane算法)等方法:
- **分治法**:将数组 `X[1…n]` 分为 `X[1…n/2]` 和 `X[n/2 +1…n]`,递归求解子问题,包括数组 `X[1…n/2]` 的最大子数组 `S1`、数组 `X[n/2+1…n]` 的最大子数组 `S2`,然后计算跨中点的最大子数组 `S3`,数组 `X` 的最大子数组之和 `Smax = max{S1, S2, S3}`,时间复杂度为 $O(nlogn)$ [^5]。
```python
def find_max_crossing_subarray(arr, low, mid, high):
left_sum = float('-inf')
sum_val = 0
max_left = mid
for i in range(mid, low - 1, -1):
sum_val += arr[i]
if sum_val > left_sum:
left_sum = sum_val
max_left = i
right_sum = float('-inf')
sum_val = 0
max_right = mid + 1
for j in range(mid + 1, high + 1):
sum_val += arr[j]
if sum_val > right_sum:
right_sum = sum_val
max_right = j
return max_left, max_right, left_sum + right_sum
def find_max_subarray(arr, low, high):
if high == low:
return low, high, arr[low]
else:
mid = (low + high) // 2
left_low, left_high, left_sum = find_max_subarray(arr, low, mid)
right_low, right_high, right_sum = find_max_subarray(arr, mid + 1, high)
cross_low, cross_high, cross_sum = find_max_crossing_subarray(arr, low, mid, high)
if left_sum >= right_sum and left_sum >= cross_sum:
return left_low, left_high, left_sum
elif right_sum >= left_sum and right_sum >= cross_sum:
return right_low, right_high, right_sum
else:
return cross_low, cross_high, cross_sum
arr = [13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]
low, high, max_sum = find_max_subarray(arr, 0, len(arr) - 1)
print(f"最大子数组的起始下标: {low}, 结束下标: {high}, 最大和: {max_sum}")
```
- **Kadane算法**:从数组左边界开始,由左到右处理,记录到目前为止已处理过的最大子数组。若已知 `A[1...j]` 的最大子数组,`A[1...j+1]` 的最大子数组要么是 `A[1...j]` 的最大子数组,要么是某个子数组 `A[i...j+1]` 的最大子数组(`1 <= i <= j+1`),在已知 `A[1...j]` 的最大子数组的情况下,可以在线性时间内找出形如 `A[i...j+1]` 的最大子数组,时间复杂度为 $O(n)$ [^1]。
```python
def max_subarray_sum(arr):
max_ending_here = max_so_far = arr[0]
for num in arr[1:]:
max_ending_here = max(num, max_ending_here + num)
max_so_far = max(max_so_far, max_ending_here)
return max_so_far
arr = [13, -3, -25, 20, -3, -16, -23, 18, 20, -7, 12, -5, -22, 15, -4, 7]
print(f"最大子数组和: {max_subarray_sum(arr)}")
```