问题来源:最大子序和
问题描述:给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。
例子:
输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。
1. O ( n 2 ) O(n^2) O(n2)算法
这是一种暴力算法。两层遍历将所有的可能子列表取得,并计算该子列表和。第一遍遍历,遍历以nums[i]开端的子列表;第二遍遍历,给定开端nums[i],遍历以nums[j]结束的子列表。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
res = []
# 以nums[i]为开端的子列表
for i in range(len(nums)):
# 以nums[j]为结束的子列表
# 即子列表nums[i: j]
for j in range(i+1, len(nums)+1):
temp = sum(nums[i: j])
res.append(temp)
# 返回res中的最大值
return max(res)
这种算法超时。
2. O ( n ) O(n) O(n)算法
实际上,暴力算法里有很多重复计算,比如,以nums[0]为开端的子列表,实际上包含了以nums[1]为开端的子列表计算,也就是说,计算以nums[0]为开端的子列表,可以通过计算以nums[1]为开端的子列表得到。
动态规划:状态定义,状态转移方程,边界值。
- 状态定义: d ( i ) d(i) d(i),以nums[i]为开端的最大子序和
- 状态转移方程:
d ( i ) = { n u m s [ i ] if d ( i + 1 ) < 0 n u m s [ i ] + d ( i + 1 ) if d ( i + 1 ) ≥ 0 d(i)=\left\{ \begin{array}{lll} nums[i] &\text{if}& d(i+1)<0\\ nums[i]+d(i+1) &\text{if}& d(i+1)\ge0\\ \end{array}\right. d(i)={nums[i]nums[i]+d(i+1)ififd(i+1)<0d(i+1)≥0 - 边界值:
d ( i ) = { n u m s [ − 1 ] if i = l e n ( n u m s ) − 1 0 if i ≥ l e n ( n u m s ) d(i)=\left\{ \begin{array}{lll} nums[-1] &\text{if}& i=len(nums)-1\\ 0 &\text{if}& i\ge len(nums)\\ \end{array}\right. d(i)={nums[−1]0ififi=len(nums)−1i≥len(nums)
代码如下。
class Solution:
def maxSubArray(self, nums: List[int]) -> int:
d = [False for i in range(len(nums))]
# 遍历每一个以nums[i]为开端的最大子序和
for i in range(len(nums)-1, -1, -1):
if i == len(nums) - 1:
d[-1] = nums[-1]
else:
d[i] = nums[i] if d[i+1] < 0 else nums[i] + d[i+1]
# 选出其中最大值
return max(d)