【剑指offer】连续子数组的最大和
动态规划
连续子数组的最大和:
题目描述
输入一个整型数组,数组里有正数也有负数。数组中的一个或连续多个整数组成一个子数组。求所有子数组的和的最大值。要求时间复杂度为 O(n).
⭐思路:
最大子数组的和一定是由当前元素和之前最大连续子数组的和叠加在一起形成的,因此需要遍历n个元素,看看当前元素和其之前的最大连续子数组的和能够创造新的最大值。
根据代码可以画出一个表格用来记录递归行为,可以更好的理解动态规划的细节,array[i]为测试用例:
max用来记录最大值,newMax用来记录局部的最大值吧,dp[i]维护array前 i 个数的相加
i=1、2时,因为0、1加起来时负值,newMax当前最大值相当于012相加,结果肯定比比array[i]小,dp[i]就去记录array[i],相当于吧0、1给“甩掉”。
i=4的时候,虽然也是负值,newMax还是大于array[i]的,dp还是把当前值记录下来,除非这个newMax这个记录前 i 次记录和的值,比array[i]当前值小,否则一直“保留”。
public class Solution {
public int FindGreatestSumOfSubArray(int[] array) {
int len = array.length;
int[] dp = new int[len];
int max = array[0];
dp[0] = array[0];
for(int i=1; i < len; i++){
int newMax = dp[i-1] + array[i];
if(newMax > array[i]) {dp[i] = newMax; }
else {dp[i] = array[i]; }
if(dp[i] > max) {max = dp[i]; }
}
return max;
}
}
继续优化一下:
dp[n]代表以当前元素为截止点的连续子序列的最大和,如果dp[n-1]>0,dp[n]=dp[n]+dp[n-1],因为当前数字加上一个正数一定会变大;如果dp[n-1]<0,dp[n]不变,因为当前数字加上一个负数一定会变小。使用一个变量max记录最大的dp值返回即可。
public int FindGreatestSumOfSubArray(int[] array) {
int max = array[0];
for (int i = 1; i < array.length; i++) {
array[i] += array[i - 1] > 0 ? array[i - 1] : 0;//如果当前项加前一项小于0,就不要前面的
max = Math.max(max, array[i]);
}
return max;
}
写在最后
距离上次更新博客过去了三个月,去年考完试复习的昏天黑地,考完试只想轻松一下,回家后正好过节,断断续续的看了看jvm和机器学习的算法,在过节的气氛里没想起来写博客,知道开学以后才想起来自己还有个博客。我在找东西的时候发现,现在的博客都大差不差,冗余的东西太多了,很多东西与其说是写给别人的,不如说是写给自己的,除了自己别人看了一头雾水,能学到啥玩意。我写博客也是这样,写一篇好的博客需要花时间花精力,排版布局码字,而我还只是一个初学者,学习就已经花了我很多精力了,我尽量在学习之余,尽最大的可能写出让自己能理解,别人也能理解的博客,因为写博客不仅仅时为了让自己理解。
当初写博客,想着是对自己学习的一种总结,据“艾宾浩斯遗忘曲线”的理论,学习指望前看不会顾,效率是很低的,所以说温故而知新,希望我2021的学习之路,能够再提升一下自己的学习效率。其实学习本身就是一门学问,磨刀不误砍柴工。
我看到天天更新的博主,很惊讶他是如何坚持下来的,看到更着更着突然不更的博主,又挺好奇他跑到哪里去了,是不是账号忘了😂 不知道今年年末的时候,我再打开我的博客,那时候会是个什么样,我又会感慨什么。又在如果,十年之后?
如果学完一天有精力的话,我会更新一下,总结自己学习的经验,也是学习的过程。如果没力气不想更了,就什么时候想更了再说。这东西其实都看自己,没有人逼着我更新或是每天都有个指标,更博客也没钱赚哈哈。我反思了一下自己的想法,我觉得我只是想做的更好一点,不过可能也是这一点让我“找到了局部最优点却忽略了全局最优点”,谁知道呢?
温故而知新,与君共勉。