赞
踩
[博客为作者复习笔记]
Kadane算法
动态规划
滑动窗口
适用于解决子数组最大和问题
拆解状态,构造转移过程(动态规划)
局部最优 与 全局最优 关系判断、证明 (贪心)
要想知道最大和子数组。最简单的是暴力,那先分析这个方法。
用左右边界状态存储数组和 Sum[Lenth][Lenth]
当前数组和 =除去最后元素的前缀数组和 +当前元素
那优化一下。怎么求这个所有子数组的和构成的集合?
让我们更方便用公式总结。
当前数组子数组和的集合 ={ 除去最后元素的前缀数组子数组和的集合+当前元素,当前元素}
那怎么样将最大Sum,MaxSonSum求出来呢?
一种巧妙的贪心递推:
最大子数组和 = max(max(当前子数组和集合),最大子数组和)
(维护DP表)当前子数组和集合 的 最大值 = 最大子数组和(非必要)
公式:
问题1:
MaxSonSum[l][r] =max(MaxSonSum[l][r-1]+Data[r],Data[r]) 你觉得他对吗?
不,它不对。因为DP[l][r]>DP[l][r-1]不一定成立,没有这个单调性也就没有办法求全局最优因此你必须需要一个维护全局最优的数据 GlobalMaxSum
问题2:
Global只需要在最后赋值给DP[l][r]就可以了吗。
对于这个问题关键看你的DP结构是什么。
如果你只是想要最终结果,完全可以用一个变量GlobalMaxSum来维护,因此也不需要,也没有DP表格,
如果你要维护DP表以优化查询,那就要确保DP表是正确的。这时候就要确保每步保存局部最优。对每个DP进行GlobalMaxSum赋值。
GlobalMaxSum能保证最终的全局解符合题意。那你要知道DP[l][r]是要靠前面的数据DP[l][r-1]来得到结果的。那DP[l][r-1]又是怎么求的?他也是需要一个GlobalMaxSum,或者说DP表,所以说这又是一个递推的问题。对此要在每一个DP[l][r]计算时都要为其取全局最优。递推保证过程严谨。而选择DP表还是GlobalMaxSum变量来维护就看具体需要了。
问题3:
DP表结构是什么样子 。
理解递推。这样说来我们就可以看出来DP的(边界)起点与终点了。起点是每一个
DP[i][i],终点是DP[i][R]
实际上,你观察后会发现每个DP[0][R]求值时只会用到同一行,也就是前缀最大子数组和,
也就是某些情况下可做些取舍:
伪代码:
- 当查询次数较少可以计算尽量少的数据来求解,以保证效率
A: (标准Kadane)
GlobalMaxSum = max(GlobalMaxSum,max(CurrentSum+Data[n],Data[n]))
B: (一维DP式Kadane)
GlobalMaxSum = max(GlobalMaxSum,max(DP[n-1]+Data[n],Data[n] ))
- 当查询次数多且任意子数组时,可以维护二维DP表,以保证查询效率
(可查询DP实现Kadane)
GlobalMaxSum = max(max(DP[l][r-1]+Data[r],Data[r]),GlobalMaxSum)) DP[l][r] = GlobalMaxSum
- 如果只是单边界变化的子数组时,可以维护一维DP表
(可查询二维DP实现Kadane)
GlobalMaxSum = max(max(DP[n-1]+Data[n],Data[n),GlobalMaxSum) DP[n]= GlobalMaxSum注意:每一行GlobalMaxSum都是要置零刷新的,因为每行都是独立的需要单独计算,互不依赖
滑动窗口的核心就是利用窗口在拓展上的单调性以及窗口收缩的条件性
Kadnae
[不进行存储]
- int kadane(const std::vector<int>& nums) {
- int max_current = nums[0];
- int max_global = nums[0];
-
- for (size_t i = 1; i < nums.size(); ++i) {
- max_current = std::max(nums[i], max_current + nums[i]);
- if (max_current > max_global) {
- max_global = max_current;
- }
- }
- return max_global;
- }
模版复习与优化 : 理解熟悉算法过程
理解其拓展性 : 理解背后的核心思想
刷题提高应用性 : 提高对题目描述的敏感度
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。