当前位置: 首页 > news >正文

子数组最大累加和dp问题I(保姆级!)

1.前言

之前写的博客都是站在已经解出题目的角度,有些分析过程很短,而且比较晦涩。

这篇站在做题者的角度,一步一步分析,一步一步讲解

2.连续子数组的最大和

1.一个常识

题目要求一个最大的连续子数组和

因为每一个子数组必然有一个结束的地方,结束的地方一定是0到nums.size()-1之间的一个

所以只需要分别求出以每一个位置结尾的子数组的最大和,再选出最大的就行了

dp[i]:以i位置为结尾的子数组(必须含有i )最大和,下面推断递推式:

2.用一个例子自行感受一下(感受不出可以边看“3”边感受)

nums = {1,2,3,-4,-9,1}

索引  =   0,1,2,3, 4, 5

直观来看,dp[0] = 1,dp[1] = 2 + 1 = 3,dp[2] = 3 + 2 + 1 = 6;

dp[3] = -4 + dp[2] = 6,dp[4] = -9 + dp[3] = -6,dp[5] = 1;

3.具体分析递推公式

  以i位置为结尾的子数组最大和,就是两种情况,要么选择1)往前囊括,要么2)孤寡一人。

1)如果往前囊括,势必要把i-1位置的数囊括进来,那囊括的东西总共就是nums[i] + nums[i-1] + ...

nums[i]是确定的,只需nums[i-1] + ...取得最大值,这不就是dp[i-1]吗?

2)如果孤寡一人,就是nums[i]

取1)和2)之中的较大值,就是dp[i]

因此:dp[i] = max(nums[i],nums[i] + dp[i-1]);

4.注意初始状况

这里的边界指的是得单独确定的地方,就是dp[0],它要直接给出,后面的dp[1]的递推式中要用到dp[0],然后dp[2]用dp[1],以此类推。最后所有的dp值才能顺次推出。

dp[0] :表示的就是以0为结尾的子数组,所以dp[0] = nums[0]

5.代码详解

class Solution {
public:int maxSubArray(vector<int>& nums) {int dp[100007];dp[0] = nums[0];int maxNum = nums[0];for(int i = 1;i < nums.size();i ++){dp[i] = max(nums[i],dp[i-1]+nums[i]);maxNum = max(maxNum,dp[i]);}return maxNum ;}
};

dp数组定义100007,因为题目里面说了nums.length最大10的5次方

然后dp[0] 赋值为nums[0]

maxSum用于记录遍历dp时的最大值,初始值设为dp[0],也就是nums[0]

循环遍历nums数组,利用递推式更新dp数组。然后看看当前dp[i]是否大于maxSum,如果大于,更新maxSum为当前dp[i]

返回maxSum

6.空间优化:我们发现,dp[i]的计算仅仅依赖dp[i-1],

若是我们设置一个变量,int cur = dp[0],再计算dp[1]的时候,只要有cur就行了,计算出dp[1]之后,只需要把dp[1]赋值给cur,然后就能计算出dp[2],.......

我们通过一个变量的“滚动”代替了一个数组!

        int cur = nums[0];int maxNum = nums[0];for(int i = 1;i < nums.size();i ++){cur = max(nums[i],cur + nums[i]);maxNum = max(maxNum,cur);}return maxNum;

7.这道题还有别的方法,会在之后的“归并分治”博客中讲解

3.不能取相邻元素的子序列的最大值

1.沿袭

我们还是可以把问题转为求各个以i做结尾(子序列必须包含i)的子序列,然后选择最大的即可

2.递推公式

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

由于取得元素不能相邻,如果取了当前位置i的元素,必然不能取i-1。

1)如果取了i-2,那么问题就转化成了求以i-2做结尾的最大值+nums[i],即dp[i-2]+nums[i]

2) 如果取了不取i - 2,取 i -3,同理,问题转化为dp[i-3]+nums[i]

3)还有情况吗?如果不取i-2,i-3,而是取i-4行吗?

取i-4,i-4和i之间的i-2也能取。而且必然是算上i-2会“更好一些”,因为题目规定nums中的元素都是非负数!

因此3)不如1)优秀,我们要比较最大值,肯定舍弃3)!

再往下,以此类推,要么不如1),要么不如2)!

“不严谨的”证明了递推式的正确性,其实动态规划有时候就是猜出来的。。。

3.边界情况

考虑到递推式中涉及i-3,所以至少得把dp[0],dp[1],dp[2],dp[3]列出

dp[0] = nums[0];

dp[1] = nums[1];//由于不能取相邻的,dp[1]只能取nums[1]

dp[2] = max(nums[2],nums[2]+nums[0])

dp[3] = max(nums[3],nums[3]+nums[1],nums[3]+nums[0]//注意这里一定不要忘了可以连续跳两个,选择0和3,不要少了第三项!!

4.代码

class Solution {public:int rob(vector<int>& nums) {int dp[102];int maxSub = nums[0];dp[0] = nums[0];if(nums.size() >= 2)dp[1] = nums[1];maxSub = max(maxSub,dp[1]); if(nums.size() >= 3)dp[2] = nums[0] + nums[2];maxSub = max(maxSub,dp[2]);if(nums.size() >= 4)dp[3] = max(nums[0] + nums[3],nums[1] + nums[3]);maxSub = max(maxSub,dp[3]);for(int i = 4;i < nums.size();i ++){dp[i] = max(dp[i-2] + nums[i],dp[i-3] + nums[i]);maxSub = max(maxSub,dp[i]);}return maxSub;}};

列出所有边界情况然后执行循环就行,和上面那题差不多

需要注意的是,dp2和dp3计算时没有和nums[2],nums[3]比较,还是因为题目中说数组中全是非负数,因此nums[0] + nums[2] >= nums[2],nums[1]+nums[3] >= nums[3]。

这道题同样可以不开数组dp,选择使用三个变量pre3,pre2,pre1来记录dp[i-3],dp[i-2],dp[i-1]

你不妨试试!


文章转载自:

http://kKPK2MDd.ynstj.cn
http://H9dME762.ynstj.cn
http://uLoVYsOG.ynstj.cn
http://vS9Myo4d.ynstj.cn
http://4IjGsCRp.ynstj.cn
http://KrXYVvoV.ynstj.cn
http://sHLA4JPQ.ynstj.cn
http://MXZIu66u.ynstj.cn
http://Qm1N545G.ynstj.cn
http://Me4AREvM.ynstj.cn
http://sNLJ6OIJ.ynstj.cn
http://XX3MVxZ8.ynstj.cn
http://BxYnae3M.ynstj.cn
http://NrH6lirT.ynstj.cn
http://mZUoSGE9.ynstj.cn
http://Xk0mwcRI.ynstj.cn
http://TREjyWeK.ynstj.cn
http://0W9uk0KP.ynstj.cn
http://JPamnH1s.ynstj.cn
http://lHg7D6ft.ynstj.cn
http://fAePSAlq.ynstj.cn
http://LXbGklJi.ynstj.cn
http://7IUrBSIg.ynstj.cn
http://uxoCTZNY.ynstj.cn
http://nv6Fwgyi.ynstj.cn
http://hwimfldb.ynstj.cn
http://uaODXf35.ynstj.cn
http://3EiMSRoX.ynstj.cn
http://nk0HUvnz.ynstj.cn
http://dXyU7kOJ.ynstj.cn
http://www.dtcms.com/a/378398.html

相关文章:

  • Win10和Win11打开IE浏览器
  • 解锁Python超能力:面向对象编程之类继承完全指南
  • 【openGLES】纹理
  • 什么是OCSP装订(OCSP Stapling)?它如何加速SSL握手?
  • 微硕WINSOK MOS管WSF3089,赋能汽车转向系统安全升级
  • Matplotlib 动画显示进阶:交互式控制、3D 动画与未来趋势
  • 立体校正原理
  • CAD球体密堆积_圆柱体试件3D插件 球体颗粒在圆柱容器内的堆积建模
  • 西门子 S7-200 PLC SMART 模拟量指令库(Scale)添加与实战使用指南
  • 后端Web实战-Spring原理
  • 计算机网络---内网穿透
  • QTDay1 图形化界面
  • Flutter 中的 Isolate
  • 将容器连接到默认桥接网络
  • 探索AI工具宝库:Awesome AI Tools - 让AI成为你的超级助手
  • UEC++学习(十八)使用TAutoConsoleVariable<T> / FAutoConsoleCommand自定义控制台变量/命令
  • 2.9Vue创建项目(组件)的补充
  • MasterGo蒙版
  • 一次.dockerignore设置错误导致的docker build排查
  • 第六节,探索 ​​CSS 的高级特性、复杂布局技巧、性能优化以及与现代前端工作流的整合​​
  • Flink on YARN 实战问题排查指南(精华版)
  • Java全栈学习笔记34
  • 进程控制(1)
  • 操作系统进程管理——同步与互斥的基本概念
  • 灰色关联分析笔记
  • CAD文件坐标系未知?用Bigemap Pro自动计算中央子午线,准确定位!
  • 项目管理核心八项(软件篇)
  • 创新驱动:医养照护与管理实训室建设方案构建
  • C++ 之 cli窗口交互程序测试DLL
  • openEuler系统远程管理方案:cpolar实现安全高效运维