number最大长度_[前端知识点-常见算法]动态规划(DP)解最大连续子序列

5545ca4ea94dbcea926ccd9a4f6d4afc.png
最大连续子序列,相信大家已经在各种文章和算法题解中看到无数次这个名字了,这是一道面试中出现频率非常的题目,我在最近几年的面试中,也经常会问这道题目。
喜欢这道题目的原因就是:从易到难可以有很多种解法,而且常见解法上也有许多可以优化的点,这种可以引导候选人更好的算法,可以根据优化点继续提问的题目是比较适合面试过程中循序渐进的沟通。

题目

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

示例:

输入: [-2,1,-3,4,-1,2,1,-5,4],
输出: 6
解释: 连续子数组 [4,-1,2,1] 的和最大,为 6。

思路分析

看到这道题的第一感觉是,我可以把所有可能的子数组的和全部求出来,在两层循环的过程中记录当前的最大值即可完成题目。这样的时间复杂度是O(n^2) n是数组长度:

// 伪代码
// 外层循环是当前子序列开始的标记
for i (0 ~ arr.length)   
  //每次开始求一个新的子数组 当前求和归零
  sum = 0  
  // 内层循环是当前子序列结束的标记
  for j (0 ~ arr.length)
    // 循环过程中进行子序列求和累加
    sum += arr[j]
    // 同时记录当前的最大值max
    max = Math.max(sum, max)
// 最终返回max即可
return max

我们有了最基础也可能是比较慢的解法,我们继续来分析是否有更好更快的解法呢(比如说让时间复杂度优化成O(n))。

我们来拆解问题,去分析相关的子序列之间的关系,然后顺着这个规律去解决这个问题。首先我们的示例数组是[-2,1,-3,4,-1,2,1,-5,4]

  • 以数组第二个元素作为结尾的子序列最大值是1
    • [-2, 1] sum = -1
    • [1] sum = 1
  • 以数组第三个元素作为结尾的子序列最大值是-2
    • [-2, 1, -3] sum = -4
    • [1, -3] sum = -2
    • [-3] sum = -3
  • 以数组第四个元素作为结尾的子序列最大值是4
    • [-2, 1, -3, 4] sum = 0
    • [1, -3, 4] sum = 2
    • [-3, 4] sum = 1
    • [4] sum = 4

以此类推,我们会发现一个特点,当子序列的某个元素之前的元素和为负数时,他对后边的最大和一定是一个负向增益,没有该元素本身大。

利用这个特点,我们把目光投向整个数组,如果我们从前向后遍历,当遇到前方和为负数时,就可以抛点前边的元素,从当前元素继续向后去计算,也可以总结成一个动态规划的公式:

dp = max(dp + current, current)

当前的最优解就是取前一个元素组合的最优解加上当前值和当前值里更大的一个,废话不多说,我们直接上代码(前期的题解,我都会逐行写注释,不过大家会发现我在题目分析部分其实已经把思路讲清楚了,代码只是对思路的一种计算机语言描述)

/**
 * @param {number[]} nums
 * @return {number}
 */
let maxSubArray = function(nums) {
    // 默认当前的最大和为第一个元素
    let sum = nums[0]
    // dp代表以当前元素结尾的最大和,默认也是第一个元素
    let dp = nums[0]
    // 从数组的第二个元素开始循环
    for(let i = 1; i < nums.length; i++){
        // 上文中提到的dp公式
        dp = Math.max(dp + nums[i], nums[i])
        // 同时进行当前最大值的记录
        sum = Math.max(sum, dp)
    }
    return sum
};

看到这,你其实已经掌握了用最简单的动态规划来解决最优解问题,它的核心就是分解问题,在子解中找到状态转移方程(上文提到的dp方程),掌握了这种方法,我们之后解决类似题目的思路就是找到转态转移方程,然后爽歪歪的翻译成js代码,再考虑下边界边界。恭喜你,这道题已经解决了!

终于把我的第一篇试水文章写完了,明天的计划是进行一下题目延伸,带着大家一起来学习《动态规划解积雨问题》,快快关注我,每天晚上来学习前端知识吧!

有什么问题、建议、意见大家都可以在文章下方留言。我会第一时间回复的。如果你觉得我的文章还不错,欢迎推荐给身边的前端同学,小东更会有继续写的动力哦!快快关注我的公众号 FE前端 哦!

e76a1c4594f785c9fc1317cf21afe975.png
文章涉及到源码已经在github中开源, 请在公众号中发送“源码”获取代码地址
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值