动态规划系列之二最大和子数组

1|0动态规划之最大和子数组


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

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

1|1解题思路


使用动态方程解题就需要题目符合动态方程解法,动态方程的两个思路:

  1. 将大的问题拆解成小一点问题,小问题和大问题的解决思路是类似的
  2. 小问题之间的关系能完成大问题的最优解

1|2建立数学模型


求数组arr中最大和的子数组,建立一个子数组和的列表dp。其中dp[i]代表着以第i-1个元素结尾的数组的最大和。

一般情况下,我们可以用dp[i]代表以第 i 个元素结尾的子数组的最值,而递推关系就是考虑和dp[i-1]之间的关系

1|3边界值


dp[i]代表这以第i-1个元素结尾的子数组的最大和,所以dp[0]就是边界值。当数组只有一个元素时,该元素就是数组的最大和

1|4状态转移方程


状态转移方程是最难写的,但是我们要迎难而上。下面分析一下该状态如何转移。

这里用dp[i]代表以第 i 个元素结尾的子数组的最大和,则max(dp[i])就是要求的最终结果,那么关键是如何写出递推关系式。

转化后模型:
求i=7结尾的最大和。求i=7时,要知道前面的前一个dp[7-1]的值。比较 dp[6] + nums[7] 和 nums[7] 的大小,大的那一个就是dp[7]的值,也就是以 第7个元素结尾的子数组的最大值。

这里求8个元素的最大和的子数组,这个大问题可以拆解成小问题,即求8个元素的最大和的子数组,继续拆解可以为求7个元素的最大和的子数组,一直到求1个元素的最大和子数组。

-2,-1,-3,4,-1,2,1,-5 -2,-1,-3,4,-1,2,1 -2,-1,-3,4,-1,2 -2,-1,-3,4,-1 -2,-1,-3,4 -2,-1,-3 -2,-1 -2

小问题之间的联系,可以完成大问题的最优解。

-2 最大和就是-2
-2,-1 以-1结尾的最大和为-1,因为前i-1个元素+i元素的最大值为负数,所以最大值为当前-1
-2,-1,-3 以-3结尾的最大和为-3,前2个元素+i元素的最大值为-3,相比较当前值-3,最大值就是-3
-2,-1,-3,4 以4结尾的最大和为4,前3个元素的最大和-3为负数,但没第4个元素,所以最大的和为4
-2,-1,-3,4,-1 以-1结尾的最大和为3,前4个元素的最大和为4,所以加上当前值能变大,最大和为3
-2,-1,-3,4,-1,2 以2结尾的最大和为5,前5个元素的最大和为3,所以加上当前值能变大,最大和为5
-2,-1,-3,4,-1,2,1 以1结尾的最大和为1,前6个元素的最大和为5,加上当前值为6,
-2,-1,-3,4,-1,2,1,-5 以-5结尾的最大和1,前7个元素的最大和为1,大于0,所以加上当前元素能变大,最大和为1

统计出所有以第i个元素结尾的最大和为

-2 -1 -3 4 -1 2 1 -5
-2 -1 -3 4 3 5 6 1

可以看出当以1结尾时,可以获得最大和的子数组,值为6

明显的,因为我们考虑的子数组以nums[i]结尾,那么该数组一定是包含nums[i]这个元素的,因此需要考虑两种情况:即nums[i]单独成为一段还是与前面的dp[i-1]一起构成子数组,因此,可以得到如下的递推关系式:

dp[i]=max(dp[i-1]+nums[i],nums[i])

或者说:
dp[i-1]代表着前i-1个元素组成的子数组的最大和,那么加上第i个元素时就有两种情况:

  1. 第i个元素 大于 dp[i-1]+arr[i],那么前i个元素的最大值为第i个元素的值
  2. 第i个元素 小于 dp[i-1]+arr[i],那么前i个元素的最大值为前i-1个元素的值 + 第i个元素
dp[i] = max{arr[i], dp[i-1]+arr[i]}

1|5python代码


input_list = [-2,-1,-3,4,-1,2,1,-5] length = len(input_list) dp = [0] * length # 边界值,如果只有一个元素,则第一个元素的最大值就是自身 dp[0] = input_list[0] for i in range(1,len(input_list)): # if dp[i-1] + input_list[i] > input_list[i] ---> dp[i-1] > 0。或许前一种写法更容易理解 if dp[i-1] > 0: # 如果前i-1个元素的最大值大于0,那么加上当前就能使得以当前值为结尾的最大和变大 dp[i] = dp[i-1] + input_list[i] else: # 如果前i-1个元素的最大值小于0,那么加上当前就能使得以当前值为结尾的最大和变小。以当前值为结尾的最大和就是自身组成的数组 dp[i] = input_list[i] print(dp) print(max(dp))

又可以写成:

input_list = [-2,1,-3,4,-1,2,1,-5,4] length = len(input_list) # 构建一个dp数组,用来存储以第i个元素为结尾的最大子数组之和 dp = [0] * length # 边界值,如果只有一个元素,则第一个元素的最大值就是自身 dp[0] = input_list[0] for i in range(1,length): # 循环数组,比较前i-1个数组最大值+自身 和自身的大小。 # 如果大则表明前i-1个数组是正数,则可以继续加上第i个 # 如果小则表明前i-1个数组是负数,那么相加肯定更小,所以以自身为新起点继续往下走 dp[i] = max(dp[i-1]+input_list[i],input_list[i]) print(max(dp))

1|6小结


最长连续子序的解法精华在于 维护了一个dp数组,该数组中的每一个元素都代表着前i-1个元素能够组成的最大值,只需要比较前i-1个元素+第i个元素的值与第i个元素的值的大小,就能得到第前i个元素能够组成的子数组的最大值。


__EOF__

本文作者goldsunshine
本文链接https://www.cnblogs.com/goldsunshine/p/13221668.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   金色旭光  阅读(362)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示