Python 算法题之 子数组的最大和

Python 算法题之 子数组的最大和


给出题目🍠

输入一个整型数组,数组中的一个或连续多个整数组成一个子数组,求所有子数组的和的最大值

比如输入 nums = [-2,1,-3,4,-1,2,1,-5,4],其中的最大子数组是 [4,-1,2,1],算法应当输出 6

注意:
此问题要求 计算子数组的最大和,而子数组一定是连续的,这就是为什么上面的示例 最大子数组中有个 -1,而不把除了负数之外的值全部加起来,为获取最大子数组和,那就得经过 -1

此问题与此前提到的 最长递增序列比较类似


暴力算法

这道题相对简单,只要掌握如何获取并且保存 最大值即可

  • 循环每一个 nums[i:] 的值并求和,保存求和的最大值
def max_sub_array(nums: list) -> int:
    res, length = float("-inf"), len(nums)
    for i in range(length):
        res_i = 0                             # 每次循环结束,把res清0,不继承nums[i:]的最大值
        for k in range(i, length):
            res_i += nums[k]                  # 将nums[i:] 中的值循环求和
            if res < res_i:               	  # 当nums[i:] 循环求和中的结果 大于 已知最大值时,重新给最大值赋值
                res = res_i
    return max_res                            # 此时返回的是最大值
  • 时间复杂度: O(n㏒n) ,其中 for k in range(i, length) 中的 i 会随着第一层循环逐渐减少
  • 空间复杂度: O(1)

动态规划

问题要求的是子数组,而不是子序列,那么就能想出,dp[i] 只有两种选择

  • 要么与前面相邻子数值相连,要么不与前面的子数组相连,自成一派
  • 根据这两种选择,比较容易能想出,状态转移方程为 max(nums[i], nums[i]+dp[i-1]),最简单的情况下 (base case) 即为自身 nums[i]
def max_sub_array(nums: list) -> int:
    length = len(nums)
    dp = [0] * length
    dp[0] = nums[0]					# 第一个元素前面没有子数组,这里手动添加最简单的情况下自身值
    for i in range(1, length):		# 跳过dp[0],从dp[1] 开始
        dp[i] = max(nums[i], dp[i - 1] + nums[i])
    return max(dp)

当然,也可以直接给 DP Table 一个初始值 解决 第一个元素前面没有子数组的问题

def max_sub_array(nums: list) -> int:
    length = len(nums)
    dp = [0] * (length+1)           # 为 DP Table 增加一个初始值
    for i in range(1, length):
        dp[i] = max(nums[i-1], dp[i - 1] + nums[i-1])
    return max(dp)
  • 时间复杂度: O(n)
  • 空间复杂度: O(n)

存储前两个状态

仔细观察 状态转移方程,可以发现 dp[i] 只是和它的左邻居 dp[i-1] 有关系,这和 斐波那契数列 相似,斐波那契数列 只需要存储前两个状态即可,那么 最大子数组和 是否也能做到呢?

def maxSubArray(self, nums: List[int]) -> int:
    prev = res = nums[0]            # pres 代表 dp[i-1], res为dp[0]最简单的情况下自身值
    length = len(nums)
    for i in range(1, length):
        curr = max(nums[i], prev+nums[i])
        prev = curr
        res = max(res, curr)        # 保存子数组和最大值

    return res

可以看到,确实能够参考 斐波那契数列 那样只存储前两个状态 ,从而实现 状态压缩 优化

  • 时间复杂度: O(n)
  • 空间复杂度: O(1),因为只是存储前两个状态,所以从O(n)降到了O(1)

参考资料😘

由衷感谢💖


相关博客😏

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值