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

生活中的算法

想象你是一位股票交易员,手上有一支股票的每日涨跌数据。你想找出哪段连续的交易日能获得最大的收益。如果某天股票上涨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. The Bento Box Adventure

    题目来源:codeforces 2041A 题目名称:The Bento Box Adventure 题目链接:https://codeforces.com/contest/2041/problem/ ...

  2. 版本管理客户端工具SourceTree

    [使用] 1.设置SSH客户端 工具 > 选项 设置OpenSSH, SSH 密钥这一栏自然会去选择当前用户下的 .ssh 目录下的 id_rsa 这个私钥:

  3. HEUCPC2021

    stral Reflection 在 \([1,n]\)上支持如下操作: 操作一:学习一个新的技能--清除 \([l,r]\)内所有的陨石 操作二:给定一个点集\(k\)代表陨石出现在这些位置,询问最 ...

  4. RAG分块策略:主流方法(递归、jina-seg)+前沿推荐(Meta-chunking、Late chunking、SLM-SFT)

    RAG分块策略:主流方法(递归.jina-seg)+前沿推荐(Meta-chunking.Late chunking.SLM-SFT) 大多数常用的数据分块方法(chunking)都是基于规则的,采用 ...

  5. PM-CentOS7也即将停止维护,将来何去何从?

    停掉的CentOS包含三个版本,即:CentOS 6(2020年11月30日停止更新).CentOS7(2024年6月30日停止更新).CentOS 8(2021年底停止更新). 在当前处于生命周期中 ...

  6. 使用pjsip封装自定义软电话sdk

    环境: window10_x64 & vs2022pjsip版本: 2.14.1python版本: 3.9.13 近期有关于windows环境下软电话sdk开发的需求,需要开发动态库给上层应用 ...

  7. COSBrowser iOS 版 | 如何不打开 App 查看监控数据?

    您是否有遇到这样的场景?当需要实时查看存储监控数据.查看某个存储桶的对象数量,又或者想了解某一个存储类型文件的下载量在当前与前一天的对比情况,是上涨了还是下降了,这时您是否也在经历频繁的打开关闭 Ap ...

  8. 中电金信成为开源风险评估与治理技术实验室软件物料清单(SBOM)工作组成员单位

    近期,中电金信成功加入国家工业信息安全发展研究中心开源风险评估与治理技术实验室软件物料清单(SBOM)工作组,成为其成员单位,并同步加入"筑链计划"之中. SBOM是Softwar ...

  9. 自用Idea内存配置

    自用Idea内存配置 如下: 使用了zgc,自用48g内存的mac.可以应对8后端4前端同时使用. -Xms1g -Xmx12g -XX:+UseLargePages -XstartOnFirstTh ...

  10. springboot 2.x 集成quartz持久化到一个单独的dataSource时遇到的坑

    由于希望可以在集群环境中运行定时job,但考虑到多个job实例有可能带来job重复执行的问题,新项目的job打算从原生的spring task实现改成quartz job实现,并采用jdbc的存储方式 ...