Leetcode53.最大子序和【动态规划】、【分治法】

题目描述:

给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
子数组 是数组中的一个连续部分。

题目链接:53.最大子序和

【解法一】:动态规划

f [ i ] f[i] f[i]为以第i个元素结尾的最大的连续子数组的和。假设对于元素i,所有以它前面的元素结尾的子数组的长度都已经求得,那么以第i个元素结尾且和最大的连续子数组实际上,要么是以第i-1个元素结尾且和最大的连续子数组加上这个元素,要么是只包含第i个元素,
f [ i ] = m a x ( f [ i − 1 ] + n u m [ i ] , n u m [ i ] ) f[i]= max(f[i-1] + num[i], num[i]) f[i]=max(f[i1]+num[i],num[i])。可以通过判断 f [ i − 1 ] + n u m [ i ] f[i-1] + num[i] f[i1]+num[i]是否大于 n u m [ i ] num[i] num[i]来做选择,而这实际上等价于判断f[i-1]是否大于0。由于每次运算只需要前一次的结果,因此并不需要像普通的动态规划那样保留之前所有的计算结果,只需要保留上一次的即可,因此算法的时间和空间复杂度都很小

AC代码【Python】:

    # 动态规划
    def maxSubArray(self, nums: List[int]) -> int:
        if not nums:
            return 0
        pre = 0
        maxAns = nums[0]
        for i in nums:
            pre = max(pre + i, i)
            maxAns = max(maxAns, pre)
        return maxAns

【解法二】:分治法

分治法,最大子序和要么在左半部分,要么在右半部分,要么就横跨两部分(即包括左半部分的最后一个元素,和右半部分的第一个元素)。返回这三种情况的最大值即可。第三种情况,其中包括左半部分最后一个元素的情形,需要挨个往前遍历,更新最大值。包含右半部分的第一个元素的情况类似。总的时间复杂度O(nlogn)

AC代码【Python】:

    # 分治法
    def maxSubArray(self, nums: List[int]) -> int:

        # 主函数
        left = 0
        # 左右边界
        right = len(nums) - 1
        # 求最大和
        maxSum = self.divide(nums, left, right)
        return maxSum

    def divide(self, nums, left, right):
        # 如果只有一个元素就返回
        if left == right:
            return nums[left]
        # 确立中心点
        center = (left + right) // 2
        # 求子序在中心点左边的和
        leftMaxSum = self.divide(nums, left, center)
        # 求子序在中心点右边的和
        rightMaxSum = self.divide(nums, center + 1, right)

        # 求子序横跨2边的和,分成左边界和和右边界和
        leftBorderSum = nums[center]
        leftSum = nums[center]
        for i in range(center - 1, left - 1, -1):
            leftSum += nums[i]
            if leftSum > leftBorderSum:
                # 不断更新左区块的最大值
                leftBorderSum = leftSum

        rightBorderSum = nums[center + 1]
        rightSum = nums[center + 1]
        for i in range(center + 2, right + 1):
            rightSum += nums[i]
            if rightSum > rightBorderSum:
                # 不断更新右区块的最大值
                rightBorderSum = rightSum
        # 左边界的和 + 右边那块的和
        BorderSum = leftBorderSum + rightBorderSum
        return max(leftMaxSum, rightMaxSum, BorderSum)

虽然这道题在Leetcode中标记为简单题,但是此题的dp和分治解法值得学习

参考:

Leetcode详解
脚本之家详解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值