力扣-最大子数组和

179 阅读3分钟

最大子数组和问题探讨

一道简单但也考验技巧的题

问题描述

给定一个整数数组 nums,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。子数组是数组中的一个连续部分。

思路讲解

方法一:暴力法

最简单的思路是使用暴力法,即枚举所有可能的子数组,然后计算出它们的和,最后返回最大的和。但是这种方法的时间复杂度是 O(n^2),当数组很大时,这种方法会非常慢。很显然,几乎没人会这么做。

方法二:动态规划

动态规划是解决这类问题的常用方法。它的基本思想是,对于数组中的每个元素,我们都可以选择将其加入到当前的子数组中,或者将其作为新的子数组的开始。我们可以用两个变量来记录当前子数组的和和最大子数组和。

方法三:卡迪兰算法

卡迪兰算法是动态规划的一种特殊情况,它的思想是在每一步中考虑当前元素对当前子数组和的贡献,决定是创建一个新的子数组还是将当前元素添加到现有子数组中。

方法讲解

动态规划方法

动态规划的思路可以用以下的伪代码来表示:

初始化 max_far = nums[0]
初始化 max_ending = nums[0]
对于 i = 1 到 n-1:
    max_ending = max(nums[i], max_ending + nums[i])
    max_far = max(max_far, max_ending)
返回 max_far

其中,max_far 用于记录到目前为止遇到的最大的子数组和,而 max_ending 用于记录以当前元素结尾的子数组和。在每次迭代中,我们更新这两个变量:

  • max_ending 被更新为当前元素和 max_ending + nums[i] 中的较大值。
  • max_far 被更新为 max_far 和 max_ending 中的较大值。

这样,我们可以在一次遍历后找到最大的子数组和。

卡迪兰算法

卡迪兰算法的思路可以用以下的伪代码来表示:

解释
初始化 max_far = nums[0]
初始化 max_ending = nums[0]
对于 i = 1 到 n-1:
    max_ending = max(nums[i], max_ending + nums[i])
    max_far = max(max_far, max_ending)
返回 max_far

在这个实现中,max_far 用于记录到目前为止遇到的最大的子数组和,而 max_ending 用于记录以当前元素结尾的子数组和。在每次迭代中,我们更新这两个变量:

  • max_ending 被更新为当前元素和 max_ending + nums[i] 中的较大值。
  • max_far 被更新为 max_far 和 max_ending 中的较大值。

这样,我们可以在一次遍历后找到最大的子数组和。这个算法不仅效率高,而且实现起来也非常简洁。

代码实现

动态规划方法

var maxSubArray = function (nums) {
    let max_far = nums[0];
    let max_ending= nums[0];

    for (let i = 1; i < nums.length; i++) {
        max_ending = Math.max(nums[i], max_endin + nums[i]);
        max_far = Math.max(max_far, max_ending);
    }
    return max_far;
};

卡迪兰算法

var maxSubArray = function (nums) {
    let max_far = nums[0];
    let max_ending = nums[0];

    for (let i = 1; i < nums.length; i++) {
        max_ending = Math.max(nums[i], max_ending + nums[i]);
        max_far = Math.max(max_far, max_ending);
    }
    return max_far;
};

总结

暴力法虽然简单,只能说头脑简单,算了不用。动态规划和卡迪兰算法都能在 O(n) 的时间复杂度内解决问题,其中动态规划是通用的方法,而卡迪兰算法是动态规划的一种特殊情况,它更加简洁高效。在实际应用中,可以根据问题的具体情况选择合适的方法。