最大子数组(分治法)

题目

剑指 Offer 42. 连续子数组的最大和 - 力扣(LeetCode) (leetcode-cn.com)

题解

最大子数组,但是分治法 - 连续子数组的最大和 - 力扣(LeetCode) (leetcode-cn.com)

注意考虑两侧的情况

image-20220411172120603

解题思路

见《算法导论》P70

如果把原数组分成两部分

左:[low,mid] 和右: [mid+1,high]

分别对左右部分求最大子数组

那么就有3种情况

  1. 左半部分的最大子数组就是原数组的最大子数组

  2. 右半部分的最大子数组就是原数组的最大子数组

  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
 
}

posted @ 2022-04-12 00:17  lucky_doog  阅读(61)  评论(0编辑  收藏  举报