最大子序和
问题描述:
给定一个整数数组 nums
,要求找到一个连续的子数组(至少包含一个元素),使得该子数组的和最大。返回这个最大和
输入: [-2,1,-3,4,-1,2,1,-5,4]
输出: 6
解释: 子数组 [4,-1,2,1] 的和最大,为 6。
解决方法
这个问题可以使用动态规划来求解。
动态规划转移方程:
-
状态定义:
dp[i]
表示到nums[i]
时的最大子数组的和。 -
转移方程:对于每一个
i
,有两种选择:-
选择当前元素,也就是
nums[i]
单独作为子数组的开始。 -
或者将当前元素
nums[i]
加入到之前的子数组中。
所以,递推关系为:
dp[i]=max(dp[i−1]+nums[i],nums[i])
即:
-
如果
dp[i-1] + nums[i]
比nums[i]
更大,表示我们将当前元素加到之前的子数组中。 -
否则,我们从当前元素开始一个新的子数组。
-
边界条件:
-
初始化时,
dp[0] = nums[0]
,因为子数组的和就是第一个元素本身。
最终结果:
-
最终的最大子数组和就是
dp
数组中的最大值。
代码实现:
dp
会随着数组的遍历而动态变化,可能会从较大的值变成较小的值,尤其是当我们遇到一些负数时。
由于我们每一步都在计算“到当前位置为止的最大子数组和”,所以 dp
有可能会减少。
为了确保我们能够找到全局的最大子数组和,我们需要一个全局变量(通常是 maxSum
)来保存我们迄今为止遇到过的最大值。
function maxSubArray(nums) { // 初始化第一个元素 let dp = nums[0]; let maxSum = dp; // 从第二个元素开始遍历 for (let i = 1; i < nums.length; i++) { dp = Math.max(dp + nums[i], nums[i]); // 当前子数组和和当前元素 maxSum = Math.max(maxSum, dp); //更新全局的最大子数组和 } return maxSum; } console.log(maxSubArray([-2, 1, -3, 4, -1, 2, 1, -5, 4])); // 输出 6 console.log(maxSubArray([-1, -2, -3, -4])); // 输出 -1 console.log(maxSubArray([5, 4, -1, 7, 8])); // 输出 23