最大子数组(分治法)
题目
剑指 Offer 42. 连续子数组的最大和 - 力扣(LeetCode) (leetcode-cn.com)
题解
最大子数组,但是分治法 - 连续子数组的最大和 - 力扣(LeetCode) (leetcode-cn.com)
注意考虑两侧的情况
解题思路
见《算法导论》P70
如果把原数组分成两部分
左:[low,mid] 和右: [mid+1,high]
分别对左右部分求最大子数组
那么就有3种情况
-
左半部分的最大子数组就是原数组的最大子数组
-
右半部分的最大子数组就是原数组的最大子数组
-
原数组的最大子数组跨越了左右两个部分
1 2 两种情况可以直接调用 maxSubArray 递归求解
情况 3 需要进行计算
若最大子数组跨越了左右两部分,那么最大子数组可以表示成
[i,mid] [mid+1,j]
而 [i,mid] 是左半部分以 arr[mid] 为结尾的最大子数组
而 [mid+1,j] 是右半部分以 arr[mid+1] 为开头的最大子数组
代码(golang)
func maxSubArray(nums []int) int {
return maxSubarray(nums,0,len(nums)-1)
}
func maxSubarray(arr []int, low, high int) int {
if low == high {
? return arr[low]
} else {
? mid := (low + high) / 2
? var leftMax, rightMax, crossMax int
? leftMax = maxSubarray(arr, low, mid)
? rightMax = maxSubarray(arr, mid+1, high)
? crossMax = maxCrossingArray(arr, low, mid, high)
? if leftMax >= rightMax && leftMax >= crossMax {
? return leftMax
? } else if rightMax >= leftMax && rightMax >= crossMax {
? return rightMax
? } else {
? return crossMax
? }
}
}
func maxCrossingArray(arr []int, low, mid, high int) int {
var leftSum, rightSum, sum int
var i int
leftSum = int(math.Inf(-1))
rightSum = leftSum
sum = 0
for i = mid; i >= low; i-- {
? sum = sum + arr[i]
? if sum > leftSum {
? leftSum = sum
? }
}
sum = 0
for i = mid + 1; i <= high; i++ {
? sum = sum + arr[i]
? if sum > rightSum {
? rightSum = sum
? }
}
return leftSum + rightSum
}