[53][简单][动态规划][分治] 最大子序和

题目描述

53. 最大子序和 剑指 Offer 42. 连续子数组的最大和

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

示例:

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

进阶:

如果你已经实现复杂度为 O(n) 的解法,尝试使用更为精妙的分治法求解。

解题思路

解题思路: 最大子序和

动态规划

f(i)f(i)状态表示以第ii个数结尾的连续子数组的最大和, 显然最后的结果就是maxf(i)\max{f(i)}.

以第ii个数的角度考虑, 如果能与前一位连在一起, 要求前一位f(i1)f(i-1)必须不小于0, 否则与前面相加会变小, 肯定不会是连续最大和对应子数组的一部分. 如果第ii个数是后续某个数连续最大和对应的子序列的一部分, 那肯定是不包含ii之前的部分.

因此对应的状态转移方程为:

f(i)=max{f(i1)+ai,ai}f(i)=\max\{f(i-1)+a_i, a_i\}

得到一个时间复杂度为O(n)O(n), 空间复杂度为O(n)O(n)的算法.

可以使用滚动数组思想, 进一步节省空间. 由于每一步只使用上一步的结果, 因此只要保存上一步的ff即可, 空间复杂度压缩为O(1)O(1).

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 0:
            return 0

        a, total = -1e12, -1e12
        for num in nums:
            a = max(num + a, num)
            total = max(a, total)
        return total

分治

分治的思路参考解题思路: 最大子序和中的方法二.

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        n = len(nums)
        if n == 0:
            return 0
        l, r, m, s = self.sub_array(nums, 0, n - 1)
        return m

    def sub_array(self, array, start, end):
        if start == end:
            t = array[start]
            return t, t, t, t  # left, right, max, sum

        mid = (start + end) // 2
        ll, lr, lm, ls = self.sub_array(array, start, mid)
        rl, rr, rm, rs = self.sub_array(array, mid + 1, end)
        l = max(ll, ls + rl)
        r = max(rr, rs + lr)
        m = max([lm, rm, lr + rl])
        s = ls + rs
        return l, r, m, s

最后更新于