DP-leetcode53-最大子序和(dp和分治法)

题目:

给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

思路:

连续子数据就是一个开始和结尾的区间,可以把当前元素作为区间的结尾来判断的话

以 i 结尾的所有子数组中,和最大的是多少?
如果 i-1<0 那么nums[i] 自己变成一个子数组,因为是取最大值,不能越加越小。
如果 i-1 > 0 那么就是i-1的最大和的值上加当前的值

所以归为两种状态:

​ 1. nums[i]

​ 2. dp[i-1] + nums[i]

​ 下一步是获取最大值,max(nums[i] + dp[i-1], nums[i])

时间复杂度O(n)

解题:

def maxSubArray(self, nums):
    if not nums:
        return 0
    res =  nums[0] #记录最大值
    for i in range(1,len(nums)):
        nums[i] = max(nums[i-1]+nums[i], nums[i])
        res = max(nums[i], res)
        return res

进阶:

分治法求解:O(nlogn)

借用一下官方大佬的图图;

在这里插入图片描述

分而治之、拆分成多个小数组、并获取最大值 最后合并最大值返回。

def cross_sum(nums, left, right, p): 
    if left == right:
        return nums[left]

    left_subsum = float('-inf')
    curr_sum = 0
    for i in range(p, left-1, -1):
        curr_sum += nums[i]
        left_subsum = max(left_subsum, curr_sum)

    right_subsum = float('-inf')
    curr_sum = 0
    for i in range(p + 1, right + 1):
        curr_sum += nums[i]
        right_subsum = max(right_subsum, curr_sum)

    return left_subsum + right_subsum

def helper(nums, left, right):
    if left == right:
        return nums[left]
    
    p = (left + right) // 2
    left_sum = helper(nums, left, p)
    right_sum = helper(nums, p + 1, right)
    cross_sum1 = cross_sum(nums, left, right, p)
    return max(left_sum, right_sum, cross_sum1)

nums = [-2,1,-3,4,-1,2,1,-5,4] 
a = helper(nums, 0, len(nums) - 1)

posted @ 2020-04-27 16:58  hornets  阅读(210)  评论(0)    收藏  举报