从股市走势到动态规划:探索最大子数组和问题

生活中的算法

想象你是一位股票交易员,手上有一支股票的每日涨跌数据。你想找出哪段连续的交易日能获得最大的收益。如果某天股票上涨5元,我们记为+5,下跌3元记为-3。找出总和最大的一段连续交易日,就是在寻找最大子数组和。

这个问题在现实生活中很常见。比如分析用户活跃度的波动趋势,研究气温变化的最大累积效应,或是评估企业连续几个月的盈利表现。

问题描述

LeetCode第53题"最大子数组和"是这样描述的:给你一个整数数组 nums,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。

例如:

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

最直观的解法:暴力枚举

最容易想到的方法是:枚举所有可能的子数组,计算它们的和,找出最大值。

让我们用一个简单的例子来理解:

nums = [1,-2,3,-1]
检查子数组 [1]:和为1
检查子数组 [1,-2]:和为-1
检查子数组 [1,-2,3]:和为2
检查子数组 [1,-2,3,-1]:和为1
检查子数组 [-2]:和为-2
...依此类推
找到最大和为3,对应子数组[3]

优化解法:动态规划

仔细思考会发现,我们在计算每个位置结尾的最大子数组和时,只需要关注前一个位置的最大子数组和是否值得接续。

类似继承资产,如果之前继承的是正资产,不管多还是少,有总比没有好。我在之前的资产基础上,加上我目前的资产或者负债。

可要是之前继承的是一笔负债,那我宁可不要,选择白手起家。

动态规划的原理

  1. 定义dp[i]为以第i个数结尾的最大子数组和
  2. 如果前面的和是正数,就值得接续;如果是负数,就重新开始
  3. 状态转移方程:dp[i] = max(dp[i-1] + nums[i], nums[i])
  4. 最终答案是dp数组中的最大值

算法步骤演示

用nums = [1,-2,3,-1]演示这个过程:

1. 处理1:
dp[0] = 1
当前最大和 = 1 2. 处理-2:
dp[1] = max(1-2, -2) = -1
当前最大和 = 1 3. 处理3:
dp[2] = max(-1+3, 3) = 3
当前最大和 = 3 4. 处理-1:
dp[3] = max(3-1, -1) = 2
最终最大和 = 3

Java代码实现

public int maxSubArray(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
} // dp[i]表示以i结尾的最大子数组和
int[] dp = new int[nums.length];
dp[0] = nums[0];
int maxSum = dp[0]; for (int i = 1; i < nums.length; i++) {
// 状态转移:要么接续前面的和,要么重新开始
dp[i] = Math.max(dp[i-1] + nums[i], nums[i]);
// 更新全局最大和
maxSum = Math.max(maxSum, dp[i]);
} return maxSum;
}

进一步优化:空间优化

观察发现,我们其实只需要前一个状态的值,不需要保存整个dp数组。

public int maxSubArray(int[] nums) {
if (nums == null || nums.length == 0) {
return 0;
} int currentMax = nums[0];
int maxSum = nums[0]; for (int i = 1; i < nums.length; i++) {
currentMax = Math.max(currentMax + nums[i], nums[i]);
maxSum = Math.max(maxSum, currentMax);
} return maxSum;
}

解法比较

让我们比较这些解法:

暴力枚举:

  • 时间复杂度:O(n²)
  • 空间复杂度:O(1)
  • 优点:直观易懂
  • 缺点:效率较低

动态规划:

  • 时间复杂度:O(n)
  • 空间复杂度:O(n)
  • 优点:高效且易于理解
  • 缺点:需要额外空间

空间优化版:

  • 时间复杂度:O(n)
  • 空间复杂度:O(1)
  • 优点:时空效率都很高
  • 缺点:代码不如dp数组版直观

扩展思考

这道题目启发我们:

  1. 当遇到"最大"/"最小"类型的问题时,考虑动态规划
  2. 寻找问题中的递推关系
  3. 关注是否可以优化空间复杂度
  4. 注意处理负数的情况

类似的问题还有:

  • 买卖股票的最佳时机
  • 乘积最大子数组
  • 环形子数组的最大和

小结

通过最大子数组和这道题,我们不仅学会了一个经典的动态规划问题的解法,更重要的是理解了如何将复杂问题分解为子问题,并利用子问题的解构建最终答案。这种思维方式在解决其他动态规划问题时也会很有帮助。

记住,当遇到需要求解"最大连续和"类型的问题时,动态规划往往能提供一个优雅而高效的解决方案!


作者:忍者算法

公众号:忍者算法

我准备了一份刷题清单,以及这些题目的详细题解,覆盖了绝大部分常见面试题。我可以很负责任地说,只要你把这些题真正掌握了,80%的算法面试都能遇到相似题目。公众号回复【刷题清单】获取~

【忍者算法】从股市走势到动态规划:探索最大子数组和问题|LeetCode 53 最大子数组和的更多相关文章

  1. LeetCode算法训练-贪心算法 455.分发饼干 376. 摆动序列 53. 最大子序和

    欢迎关注个人公众号:爱喝可可牛奶 LeetCode算法训练-贪心算法 455.分发饼干 376. 摆动序列 53. 最大子序和 前置知识 贪心算法核心是找局部最优解,通过局部最优推导出全局最优 Lee ...

  2. python常用算法(7)——动态规划,回溯法

    引言:从斐波那契数列看动态规划 斐波那契数列:Fn = Fn-1 + Fn-2    ( n = 1,2     fib(1) = fib(2) = 1) 练习:使用递归和非递归的方法来求解斐波那契数 ...

  3. 算法导论——lec 11 动态规划及应用

    和分治法一样,动态规划也是通过组合子问题的解而解决整个问题的.分治法是指将问题划分为一个一个独立的子问题,递归地求解各个子问题然后合并子问题的解而得到原问题的解.与此不同,动态规划适用于子问题不是相互 ...

  4. 五大常用算法之二:动态规划算法(DP)

    一.基本概念 动态规划过程是:每次决策依赖于当前状态,又随即引起状态的转移.一个决策序列就是在变化的状态中产生出来的,所以,这种多阶段最优化决策解决问题的过程就称为动态规划. 二.基本思想与策略 基本 ...

  5. 小旭讲解 LeetCode 53. Maximum Subarray 动态规划 分治策略

    原题 Given an integer array nums, find the contiguous subarray (containing at least one number) which ...

  6. 前端与算法 leetcode 26. 删除排序数组中的重复项

    目录 # 前端与算法 leetcode 26. 删除排序数组中的重复项 题目描述 概要 提示 解析 算法 # 前端与算法 leetcode 26. 删除排序数组中的重复项 题目描述 26. 删除排序数 ...

  7. 前端与算法 leetcode 350. 两个数组的交集 II

    目录 # 前端与算法 leetcode 350. 两个数组的交集 II 题目描述 概要 提示 解析 解法一:哈希表 解法二:双指针 解法三:暴力法 算法 # 前端与算法 leetcode 350. 两 ...

  8. Leetcode之动态规划(DP)专题-53. 最大子序和(Maximum Subarray)

    Leetcode之动态规划(DP)专题-53. 最大子序和(Maximum Subarray) 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. ...

  9. leetcode 刷题(数组篇)152题 乘积最大子数组 (动态规划)

    题目描述 给你一个整数数组 nums ,请你找出数组中乘积最大的连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积. 示例 1: 输入: [2,3,-2,4] 输出: 6 解释: 子 ...

  10. LeetCode初级算法的Python实现--动态规划

    动态规划的本质是递归:所以做题之前一定要会递归:递归式就是状态转移方程:这里将会介绍使用动态规划做题的思维方式. 统一的做题步骤: 1.用递归的方式写出代码:(此方法写的代码在leetcode中一定会 ...

随机推荐

  1. 2019-2020 ACM-ICPC Brazil Subregional Programming Contest

    D. Denouncing Mafia 给定一颗树,然后给定\(k\)个起点,对于每个起点来说,从该点到根节点的一条链都会被染色,求最多有几个点会被染色 \(3 \leq n \leq 1e5, 1 ...

  2. Android开发重要知识点

    一.网络 1.https原理 2.tcp/ip协议 三次握手:https://www.cnblogs.com/cenglinjinran/p/8482412.html 四次挥手:https://www ...

  3. IntelliJ IDEA 中 ctrl + w 一键选中双引号中的字符串内容

    记录下,之前一直知道在 IntelliJ IDEA 中快速选中一个词的快捷键是 ctrl + w,可是有时我们想一键选中双引号中的字符串内容,正好这个字符串中的内容有各种特殊字符,比如",& ...

  4. DataGridView频繁更新PLC报警信息数据源

    1.问题描述 当DataGridView频繁更新数据源时,可能会导致界面闪烁.性能下降等问题.这是因为每次更新数据源时,DataGridView都需要重新绘制和绑定数据,这是一个相对耗时的过程. 2. ...

  5. dotnet core微服务框架Jimu ~部署和调用演示

    首先运行 consul 下载 consul 以开发模式运行 consul agent -dev 2. 调试 用 Visual Studio 2022 IDE 打开项目: 右击解决方案-选择" ...

  6. 《前端运维》一、Linux基础--12网络

    这是linux部分的最后一篇内容,我们一起来学习下Linux网络. 我们先看些命令吧: ifconfig,查看与配置网络状态. netstat,查询网络状态,常用选项如下: -t,列出TCP协议端口 ...

  7. GraphQL Part VII: 实现数据变更

    我们已经可以使用各种方式来获取数据了.但是如何修改服务器端的数据呢?包括数据插入,修补,删除或者更新等等.GraphQL 的 mutation 就是负责这部分的. 在我们继续之前,我想对项目做一点调整 ...

  8. 2023 IDC中国数字金融论坛丨中电金信向行业分享“源启+应用重构”新范式

    9月8日,IDC主办的"2023 IDC中国数字金融论坛"在北京召开.中电金信受邀参会,并带来了深度数字化转型趋势之下关于应用重构的分享与洞见. 论坛重点关注金融科技创新发展趋势与 ...

  9. 2024年1月Java项目开发指南1:环境与工具准备

    准备工作 基础能力 开发能力的事咱先不谈,有两个基础技能要学一下. 1.学习使用Markdown编写文档 2.学会使用git拉取代码和提交代码 软件准备 电脑需要安装以下软件: IDEA 2023.2 ...

  10. Docker Install on Ubuntu

    https://docs.docker.com/engine/install/ubuntu/ https://docs.docker.com/compose/install/linux/