之前和同学有探讨过这个问题。下面先看题。
题目描述
给出一个仅含整数的数组a,请编写一个名为test的函数,找出其中连续且非空的一段使得这段和最大,计算出这个最大值。
输入与输出要求
输入一个含若干个整数的数组,输出其最大子段和。
测试样例
Input: [2, -4, 3, -1, 2, -4, 3]
Output: 4
说明: 子段[3, -1, 2]的和最大,最大值为4
题解
解决本题的基本思路为尝试从数组的第一项开始往后累加,并且记录每一次累加的结果(因为累加过程中可能加进去了负数,那么反倒比加上前要来得小了,所以要全部记录,最后比较大小)。如果累加结果出现负数的话,那么此次累加计数到此结束,从下一项开始将累加值归0并重新计数(假如累加结果是负数的话,再加后一项肯定比只计算它自身要来得小,导致后面的计算结果都比不计算此前的这个累加结果来得小,这就不符合题目中要求的最大值了。因此重新计数)。如此往复,在将数组遍历完成后会得到若干个累加结果,取它们中的最大值即可得出答案。
基本思路中的“累加”体现了动归的思想;“累加结果取最大值”体现了贪心的思想。
下面给出这一思路的代码实现。
通俗易懂版:
function test(a) {
let ans = a[0];
let sum = a[0];
for(let i = 1, len = a.length; i < len; i++) {
sum > 0 ? (sum += a[i]) : (sum = a[i]); //累加
ans < sum && (ans = sum); //记录最大值
}
return ans;
}
标准动归版(实际上就是以状态转移方程的形式简化了一下上面的代码):
function test(a) {
let dp = [a[0]];
for(let i = 1, len = a.length; i < len; i++) {
dp[i] = Math.max(a[i], dp[i-1] + a[i]);
}
return Math.max(...dp);
}