面试题42. 连续子数组的最大和

题目描述:

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

要求时间复杂度为O(n)。

示例1:

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

提示:

1 <= arr.length <= 10^5
-100 <= arr[i] <= 100
注意:本题与主站 53 题相同:https://leetcode-cn.com/problems/maximum-subarray/

个人思路:

这道题描述了一个最优化问题,因此可以考虑是否满足动态规划(Dynamic Programming,DP)的解题要求。

一般可以应用动态规划求解的问题具有以下几个特点(总结自《剑指Offer》):

  1. 该问题是求解一个最优化的问题,例如最大值、最小值等。
  2. 该问题的最优解依赖于一些子问题的最优解,这些子问题由整体问题分解而来。(这里的依赖关系以状态转移方程来描述)
  3. 这些子问题之间还存在相互重叠的更小的子问题。(DP算法正是利用了子问题的重叠性,重复利用之前计算的结果,从而降低计算量,提高程序的运行效率)
  4. 从上往下分析问题,从下往上求解问题。

对比以上特点,可以发现本题可以使用动态规划进行求解。下面需要完成DP的三个重要设定——状态定义、初始化以及状态转移。

  1. 状态定义:其实也就是需要设定我们想要求解的子问题,或者说我们想要记录的一些数据。状态定义可以有很多种,很多题目多种状态定义都可以得到正确的结果,状态定义无非是为了后续方便写出状态转移方程,一般而言题目待求解的问题即可作为状态定义,但也有例外,例如本题。本题要求我们求解一个数组中的所有子数组的最大和。(这里我们需要区分子数组与子序列的区别:子数组要求各个数相邻,可以看做是原数组的一个切片;而子序列不要求各个数相邻,只需要保证各个数的相对位置不变即可,可以看做是原数组一系列切片的组合。)假设我们定义状态为:dp[i] 代表数组nums[:i+1]中子数组的和的最大值,此时最终我们只需输出dp[-1]即为原问题的结果。但是这种状态定义使得我们很难去描述状态转移方程,因为问题要求求解的是子数组,我们难以直接判断nums[i]是否是最优解dp[i]的一个贡献者,此时对于nums[i+1]难以直接与dp[i]进行关联。因此,我们不妨设定状态为:dp[i]表示以nums[i]结尾的数组中子数组的和的最大值,从而方便我们定义状态转移。
  2. 初始化:DP问题中合理的初始化有利于统一边界判断,减少代码量以及出错的情况。本题最基础的情况就是一个数的数组,因此可以相应进行初始化,具体可见后续代码。
  3. 状态转移:牢记我们的状态定义(dp[i]表示以nums[i]结尾的数组中子数组的和的最大值),就不难写出状态转移方程了:dp[i+1] = max(nums[i+1], dp[i] + nums[i+1])

再完成以上设定后,即可编写代码了。我觉得DP问题中,最重要的就是状态定义,一旦状态定义完成了,一切(初始化以及状态转移)都可以围绕其构建完成,一般状态定义就可以定义为原问题的简单子问题即可。

具体代码如下:

class Solution:
    def maxSubArray(self, nums: List[int]) -> int:
        if not nums:
            return -1
        
        # dp表示以当前元素结尾的子数组的最大和
        dp = [nums[0]] * len(nums)  # 状态定义以及初始化
        
        # dp[i] = max(nums[i], dp[i - 1] + nums[i])  状态转移方程
        for i in range(1, len(nums)):
            dp[i] = max(nums[i], dp[i - 1] + nums[i])
        
        return max(dp)  # 根据状态定义求解最终原问题的结果

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值