在算法问题中,最大子数组和问题是一个经典问题。给定一个包含正数和负数的数组,任务是找到一个连续子数组,使得其元素之和最大。本文将介绍解决这一问题的两种常见方法:Kadane 算法和动态规划,并提供 JavaScript 实现。
问题描述
给定一个数组 arr
,例如 arr = [1, -2, 3, 4, -9, 6]
,我们需要找到一个连续子数组,使得其元素之和最大。例如,对于上述数组,最大子数组和为 [3, 4, -9, 6]
,其和为 4
。
方法一:Kadane 算法
Kadane 算法是一种高效的解决方案,时间复杂度为 (O(n)),空间复杂度为 (O(1))。其核心思想是通过遍历数组,动态计算当前子数组的最大和,并在遍历过程中更新全局最大和。
算法步骤:
- 初始化两个变量:
maxSum
(全局最大和)和tempSum
(当前子数组和)。 - 遍历数组中的每个元素:
- 将当前元素加到
tempSum
中。 - 如果
tempSum
大于maxSum
,则更新maxSum
。 - 如果
tempSum
小于 0,则将其重置为 0(因为负数会拖累后续子数组的和)。
- 将当前元素加到
- 返回
maxSum
。
JavaScript 实现:
function getMaxSubSum(arr) {
let maxSum = 0;
let tempSum = 0;
for (let item of arr) {
tempSum += item;
maxSum = Math.max(tempSum, maxSum);
if (tempSum < 0) tempSum = 0;
}
return maxSum;
}
let arr = [1, -2, 3, 4, -9, 6];
console.log(getMaxSubSum(arr)); // 输出: 7
方法二:动态规划
动态规划是另一种解决最大子数组和问题的方法。其核心思想是通过维护一个状态数组 dp
,其中 dp[i]
表示以第 i
个元素结尾的最大子数组和。
算法步骤:
- 初始化状态数组
dp
,其中dp[0]
为arr[0]
(如果arr[0]
大于 0,否则为 0)。 - 遍历数组中的每个元素:
- 计算
dp[i]
的值:dp[i] = Math.max(arr[i], arr[i] + dp[i - 1])
。 - 如果
dp[i]
小于 0,则将其重置为 0。
- 计算
- 返回
dp
数组中的最大值。
JavaScript 实现:
function getMaxSubSum(arr) {
if (!arr.length) return 0;
let dp = new Array(arr.length);
dp[0] = arr[0] > 0 ? arr[0] : 0;
for (let i = 1; i < arr.length; i++) {
dp[i] = Math.max(arr[i], arr[i] + dp[i - 1]);
if (dp[i] < 0) dp[i] = 0;
}
return Math.max(...dp);
}
let arr = [1, -2, 3, 4, -9, 6];
console.log(getMaxSubSum(arr)); // 输出: 7
方法对比
方法 | 时间复杂度 | 空间复杂度 | 适用场景 |
---|---|---|---|
Kadane 算法 | (O(n)) | (O(1)) | 适用于空间要求严格的场景 |
动态规划 | (O(n)) | (O(n)) | 需要记录每个位置的最大和时使用 |
总结
- Kadane 算法 是一种简洁高效的解决方案,适合大多数场景。
- 动态规划 提供了更直观的状态转移思路,适合需要记录中间结果的场景。