[LeetCode] 53. Maximum SubArray

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.
Example:
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.
Follow up:
If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

这道题要求两种解法,一种是O(N),一种是分支法O(nlogN)。其实这道题最暴力的解法是O(N2), 就是记住每一个起始位置的最大的值,显然,这不是这道题的要求。
思路一:O(N) 动态规划,想法很巧妙,

f(i) = f(i-1) > 0 ? f(i-1) + nums[i] : nums[i]

就是如果这个数之前的最大值如果是小于零的,你就重头开始,因为加了sum会变小,不如不加。如果大于零,那么就加上就。因为f(i)只和它之前的数字相关,进一步优化,就是之前的数的和的最大值加上现在这个数,再和现在这个数比较,更大,就加入,不然就舍弃之前的,只要现在这个数。

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        if not nums: return -sys.maxsize - 1
        
        cur_sum, res = 0, -sys.maxsize - 1
        for num in nums:
            cur_sum = max(cur_sum + num, num)
            res = max(cur_sum, res)
        return res

思路二, 其实这个我理解的不是很好,先把解法写在这。想求一个数组的Max subarray,一共就是要考虑三种情况

  1. 左边数列的最大连续子集和
  2. 右边数列的最大连续子集和
  3. 有包含中间点的最大的连续子集和

前两种都很好写recursive,只要是只有一个点的时候就是出口,但第三种情况就比较复杂。要得到包括中间的最大子集,可以先求从左边到中间点的最大子集和,然后求从中间点向后一位到右边的最大子集和,最后相加即可。

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        if not nums: return -sys.maxsize-1
        return self.find_max_subarray(nums, 0, len(nums) - 1)

    def find_max_subarray(self, nums, left, right):
        if left >= right: return nums[left]
        mid = left + (right - left) // 2
        left_sum = self.find_max_subarray(nums, left, mid)
        right_sum = self.find_max_subarray(nums, mid+1, right)
        crossing_sum = self.find_max_crossing_subarray(nums, left, right, mid)
        return max(left_sum, right_sum, crossing_sum)
    
    def find_max_crossing_subarray(self, nums, left, right, mid):
        if left >= right: return nums[left]
        left_sum, cur_sum = -sys.maxsize-1, 0
        for i in range(mid, left-1, -1):
            cur_sum += nums[i]
            left_sum = max(left_sum, cur_sum)
        
        right_sum, cur_sum = -sys.maxsize-1, 0
        for i in range(mid+1, right+1):
            cur_sum += nums[i]
            right_sum = max(right_sum, cur_sum)
            
        return left_sum + right_sum

posted on 2020-04-06 10:22  codingEskimo  阅读(113)  评论(0编辑  收藏  举报

导航