算法--最大连续子序列和(动态规划,分而治之)

今天在LeetCode上遇到一个求最大连续子序列和的问题,如下:
Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:
Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

先上正确答案,用动态规划处理这个问题。

首先介绍一下什么是动态规划,简单来说就是:
把多阶段过程转化为一系列单阶段问题,利用各阶段之间的关系,逐个求解。

分析一下这个问题:

设数组为a,第一个值为a[0],第二个值为a[1],以此类推,第n个值为a[n]。
设以a[i]为子序列最后一项时,连续最大子序和为F(i)。
注意:这里只指定a[i]作为最后一项,并不指定开始项,也就是说这里的F(i)是以a[i]前任意项开始,a[i]项结尾的连续整数和。

  • 当该数组中只有一个数值a[0]时,F(0) = a[0]。
  • 当该数组中有多个数值时,F(i) = max { a[i], a[i] + F(i-1) }。

写两个值看看这个方程:
F(0) = a[0]
F(1) = max{ a[1], a[1] + F(0) } = max{ a[1], a[0] + a[1] }
F(2) = max{ a[2], a[2] + F(1) } = max{ a[2], a[0] + a[1] + a[2] } 或= max{ a[2], a[1] + a[2] }
以此类推。

接下来写代码:

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function(nums) {
    let max = nums[0];
    let len = nums.length;
    if (len === 1) {
        return max;
    } else {
        let sum = 0;
        for (let i = 0; i < len; i ++) {
            sum += nums[i];
            if (sum < nums[i]) {
                sum = nums[i];
            }
            if (max < sum) {
                max = sum;
            }
        }
    }
    return max;
};

只要思路对了,写代码是再容易不过的事情啦!

补充分而治之法(递归)求解,以下为js代码:

/**
 * @param {number[]} nums
 * @param {number} left 左端开始位置
 * @param {number} right 右端结束位置
 * @return {number}
 */
maxSubArray (nums, left, right) {
      if (left === right) {
        return nums[0]
      }
      let mid = Math.floor((left + right) / 2)
      // 求左侧最大值
      let leftMax = this.maxSubArray(nums, left, mid)
      // 求右侧最大值
      let rightMax = this.maxSubArray(nums, mid + 1, right)
      let sum = 0
      let lmax = nums[mid]
      let rmax = nums[mid + 1]
      // 从中线往左遍历,取最大值
      for (let i = mid; i >= left; i--) {
        sum += nums[i]
        if (sum > lmax) {
          lmax = sum
        }
      }
      sum = 0
      // 从中线往右遍历,取最大值
      for (let i = mid + 1; i <= right; i++) {
        sum += nums[i]
        if (sum > rmax) {
          rmax = sum
        }
      }
      let midMax = lmax + rmax
      return leftMax > rightMax ? leftMax > midMax ? leftMax : midMax : rightMax > midMax ? rightMax : midMax
    }

// 调用
maxSubArray([-2, 1, -3, 4, -1, 2, 1, -5, 4], 1, 9)

=============================================
补充记录自己最开始的复杂写法:

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function(nums) {
    var arr = [];
    for (let i = 0; i < nums.length; i ++) {
        let sum = nums[i];
        for (let j = i + 1; j < nums.length; j ++) {
            sum += nums[j];
            arr.push(sum);
        }
    }
    arr.sort(function(a,b){ 
        return a-b; 
    }); 
    
    return arr[arr.length - 1];
};

我去,这是什么垃圾?把所有值都丢到一个新数组中这种智障代码真的是我写的?这样数组一大的话,arr数组将耗费巨大的内存,果不其然,提交后显示堆内存不足。

好吧,优化一下代码,如下:

/**
 * @param {number[]} nums
 * @return {number}
 */
var maxSubArray = function(nums) {
    var max = nums[0];
    var len = nums.length;
    for (let i = 0; i < len; i ++) {
        let sum = nums[i];
        for (let j = i + 1; j < len; j ++) {
            max = max > sum ? max : sum;
            sum += nums[j];
        }
        max = max > sum ? max : sum;
    }
    return max;
};

这里取消了新数组,但是此时的算法时间复杂度是O(n^2),虽然可以求出结果但是耗时过长。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值