菜鸟前端刷算法第十天

20 阅读2分钟

题目描述 - 最大子数组和

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

子数组 是指数组中的一个连续部分。

示例:

  • 输入: nums = [-2,1,-3,4,-1,2,1,-5,4],输出: 6,连续子数组 [4,-1,2,1] 的和最大,为 6
  • 输入: nums = [1],输出: 1
  • 输入: nums = [5,4,-1,7,8],输出: 23

思路分析

  • 暴力解法,双重遍历,遍历所有节点开头的所有子序列: 如数组[a, b, c, d],进行循环遍历时, [a][a, b][ a, b, c][ a, b, c, d],再从以 b 为开头的子序列开始遍历 [b] [b, c]...

代码实现:

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function(nums) {
    // max 初始值不能为0,要考虑数组有负数数据存在,如数据[-1] 会返回错误
    let max = 0;
    for(let i=0; i< nums.length; i++){
        let sum = 0
        for(let j=i; j<nums.length; j++){
            sum += nums[j]
            sum > max ? max = sum : ""
        }
    }
    return max
};

上面的暴力解法在leetcode上提交之后,毫无疑问,超出了时间限制,我们需要寻找更优解。

  • 动态规划

    我们假设 dp[ i ] 为以第i个元素结尾且和最大的连续子数组。

    对于元素 i,所有以它前面的元素结尾的子数组的长度都已经求得,那么,dp[ i ]=dp[ i-1 ] + arr[ i ]

    以第 i 个元素结尾且和最大的连续子数组实际上,要么是以第 i-1 个元素结尾且和最大的连续子数组加上这个元素,要么是只包含第 i 个元素 dp[ i ] = max(dp[i-1] + a[ i ], a[ i ])。

    我们可以通过判断 dp[ i-1 ] + a[ i ] 是否大于 a[ i ] 来做选择,而这实际上等价于判断 dp[ i-1 ] 是否大于0。

    如下图所示: WeChat9eb701b961b1aa3bd4e284f8bced8494.png 代码实现:

    /**
    * @param {number[]} nums
    * @return {number}
    */
    var maxSubArray = function(nums) {
      let ans = nums[0];
      let sum = 0;
      for(let num of nums) {
          // if(sum > 0) { 可以写成这样
          if(sum + num > num ){
              sum = sum + num;
          } else {
              sum = num;
          }
          ans = Math.max(ans, sum);
      };
      return ans;
    };