【原创·每日一题】最大子段和(DP+贪心)

509 阅读2分钟

之前和同学有探讨过这个问题。下面先看题。


题目描述

给出一个仅含整数的数组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);
}

参考资料

www.luogu.com.cn/blog/Walker…

zhuanlan.zhihu.com/p/87203356