news 2026/7/16 3:21:50

股票买卖问题

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
股票买卖问题

1、基础问题

只能选择某一天买入这只股票,并选择在未来的某一个不同的日子卖出该股票。设计一个算法来计算你所能获取的最大利润。

class Solution { public int maxProfit(int[] prices) { int n = prices.length; int pre = prices[0]; //记录可买入的最小值 int ans = Integer.MIN_VALUE; //记录当下得到的最大收益 for(int i = 0; i < n; i++){ ans = Math.max(ans, prices[i] - pre); pre = Math.min(pre, prices[i]); } return ans; } }

2、冷冻期

在满足以下约束条件——卖出股票后你无法在第二天买入股票 (即冷冻期为 1 天),你可以尽可能地完成更多的交易(多次买卖一支股票)。

在这个问题中,需要考虑两个问题:

1、卖出后的第二天是不能操作的,在这里初始化数组时可以类比打家劫舍问题的初始化;

2、可以多次买入卖出,那么第i天可能是买入/卖出状态,所以需要增加一维来记录每天可能发生的情况。

如果第i+2天是卖出状态(不持有股票), 那么可能发生的情况是:

  1. 第i+1天也不持有且没有买入操作;
  2. 第i天持有且卖出。

如果第i+2天是买入状态(持有股票),那么可能发生的情况是:

  1. 第i+1天已经持有且没有卖出操作;
  2. 第i天是未持有但是进行了买入操作。
class Solution { public int maxProfit(int[] prices) { int n = prices.length; // 含冷冻期:类比打家劫舍 //两列,分别代表pre和ans int[][] dp = new int[n + 2][2]; dp[1][1] = Integer.MIN_VALUE; for(int i = 0; i < n; i++){ // dp[t][0]:第t天结束,不持有股票的最大利润 dp[i + 2][0] = Math.max(dp[i + 1][0], dp[i + 1][1] + prices[i]); // dp[t][1]:第t天结束,持有股票的最大利润 dp[i + 2][1] = Math.max(dp[i + 1][1], dp[i][0] - prices[i]); } return dp[n + 1][0]; } }

3、手续费

你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。

迭代思路与上一个问题大致相同,区别在于没有冷冻期,所以第i+1天的收益只与第i天有关;

手续费在每次交易中只扣除一次,可以固定在卖出时扣除,便于理解。

class Solution { public int maxProfit(int[] prices, int fee) { int n = prices.length; // x:没有冷冻期 // y:0——第i天不持有股票;1——第i天持有股票 int[][] dp = new int[n + 1][2]; dp[0][1] = Integer.MIN_VALUE / 2; for(int i = 0; i < n; i++){ // 如果第i+1天为不持有股票状态,那么第i天如果也不持有,二者收益相同;如果持有,那么就可以卖出获得收益,同时要付出一定的手续费。 dp[i + 1][0] = Math.max(dp[i][0], dp[i][1] + prices[i] - fee); // 如果第i+1天为持有股票状态,那么第i天如果也持有,二者收益相同;如果不持有,那么就可以买入。 dp[i + 1][1] = Math.max(dp[i][0] - prices[i], dp[i][1]); } return dp[n][0]; } }

4、设定交易上限

设计一个算法来计算你所能获取的最大利润。你最多可以完成k笔交易。也就是说,你最多可以买k次,卖k次。

简单理解就是多了一个维度的限制——交易次数

(如果从三维角度不好理解,可以先参考空间优化的方案,直观理解一下对交易次数的约束)

我认为这里理解的难点在于初始化的部分:

  1. y的大小:交易次数j的取值范围是0,1,2,...,k,一共k+1种次数状态,数组第二维必须开到k+1才能容纳全部次数,为了不越界,数组长度开到k+2;
  2. 初始化为Integer.MIN_VALUE / 2的部分:标记所有状态初始为「不可达非法状态」——在第 0 天(无任何操作),不存在任何买卖行为,不管是持有股票、还是完成任意笔交易,都无法实现,全部置极小值。
  3. 初始化为0的部分:f[0][j][0] = 0——还没处理任何一天(i=0),视作已经完成 j 笔交易、且手上无股票,利润为 0
class Solution { public int maxProfit(int k, int[] prices) { int n = prices.length; int[][][] f = new int[n + 1][k + 2][2]; // x:第i天;y:第j次;z:第i天卖出状态——0,买入——1 // 初始化为最小值 for(int[][] s : f){ for(int [] row : s){ Arrays.fill(row, Integer.MIN_VALUE / 2); } } for(int j = 1; j <= k + 1; j++){ f[0][j][0] = 0; } for(int i = 0; i < n; i++){ for(int j = 1; j <= k + 1; j++){ f[i + 1][j][0] = Math.max(f[i][j][0], f[i][j][1] + prices[i]); f[i + 1][j][1] = Math.max(f[i][j - 1][0] - prices[i], f[i][j][1]); } } return f[n][k + 1][0]; } }

空间优化

相当于把每天的收益变化存储优化到一维,每次迭代后直接在原位置进行修改:

如果在迭代过程中发生了买入操作,就说明前一天的交易次数是j-1;如果没有操作或者卖出都不会修改交易次数(相当于由买入这个动作触发交易次数的变化)。

初始化:

  1. 初始化为Integer.MIN_VALUE / 2的部分:所有dp[j][1]持有股票状态),k>=1的初始时刻不可能持有股票,持股状态标记为不可达(极小值)。
  2. 初始化为0的部分:k为偏移设计,实际计算到k=1,所以k=0标记为不可达。
class Solution { public int maxProfit(int k, int[] prices) { // 空间优化 int n = prices.length; int[][] f = new int[k + 2][2]; for(int j = 1; j < k + 2; j++){ f[j][1] = Integer.MIN_VALUE / 2; } f[0][0] = Integer.MIN_VALUE / 2; for(int x : prices){ for(int j = k + 1; j > 0; j--){ f[j][0] = Math.max(f[j][0], f[j][1] + x); f[j][1] = Math.max(f[j - 1][0] - x, f[j][1]); } } return f[k + 1][0]; } }

变形:刚好k次完成

在迭代结束后判断f[k+1][0]是否为极小,如果是,说明小于k次就完成了交易,不满足题意。

//必须恰好k笔,取f[k+1][0],若还是极小说明凑不齐k笔,返回0 int res = f[k + 1][0]; return res < 0 ? 0 : res;

变形:至少k次完成

1、根据prices数组判断:是否可以至少完成k次交易?至多可以完成几次交易maxT?

2、后续基于maxT算收益;

3、遍历[k, maxT],找到在第几轮获得最大收益已经最大收益

class Solution { public int maxProfit(int k, int[] prices) { int n = prices.length; if(n < 2) return 0; int maxT = n / 2; int INF = Integer.MIN_VALUE / 2; int[][] f = new int[maxT + 2][2]; // 全局初始化极小 for(int j = 0; j < maxT + 2; j++){ f[j][0] = INF; f[j][1] = INF; } f[0][0] = 0; for(int x : prices){ for(int j = maxT + 1; j > 0; j--){ f[j][0] = Math.max(f[j][0], f[j][1] + x); f[j][1] = Math.max(f[j - 1][0] - x, f[j][1]); } } // 取所有额度>=k对应的最优解 int ans = 0; for(int j = k + 1; j <= maxT + 1; j++){ ans = Math.max(ans, f[j][0]); } return ans; } }

参考文献:灵神

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/16 3:18:37

中国汽车月度销量预测与市场趋势分析

1 研究背景与分析目标 汽车月度销量受到季节、品牌竞争、产品生命周期和外部环境共同影响。车系级销量预测可为库存计划、生产排期和营销资源配置提供参考。本案例不追求复杂算法&#xff0c;而是强调清晰的数据流程、合理的时间划分和可解释的结果。 2 数据来源与字段说明 …

作者头像 李华
网站建设 2026/7/16 3:15:00

Linux下uv+Playwright+Hermes桌面自动化部署实战

1. 项目概述&#xff1a;这不是“爱马仕”包包&#xff0c;而是开发者手里的自动化新武器看到标题里写着“国内快速安装hermes&#xff08;爱马仕&#xff09;”&#xff0c;别急着点开购物链接——这回真不是奢侈品导购&#xff0c;而是实打实的开发工具链落地实战。我连续两周…

作者头像 李华
网站建设 2026/7/16 3:13:13

C++并发设计模式实战:生产者-消费者、线程池与读写锁详解

1. 项目概述&#xff1a;为什么我们需要并发设计模式&#xff1f;如果你写过一段时间的C多线程代码&#xff0c;可能经历过这样的场景&#xff1a;项目初期&#xff0c;几个简单的std::thread和std::mutex就能让程序跑起来&#xff0c;逻辑清晰&#xff0c;性能也不错。但随着功…

作者头像 李华
网站建设 2026/7/16 3:12:12

LabVIEW串口通信:DTR与RTS信号控制详解

1. 串口控制线基础认知在工业自动化和仪器控制领域&#xff0c;串口通信仍然是最基础且广泛使用的通信方式之一。DTR&#xff08;Data Terminal Ready&#xff09;和RTS&#xff08;Request To Send&#xff09;作为串口通信中的硬件控制信号线&#xff0c;承担着设备间握手协商…

作者头像 李华
网站建设 2026/7/16 3:10:17

阻容降压电路原理与设计实战指南

1. 阻容降压&#xff1a;藏在电器里的"隐形节能师"每次拆开小型家电的控制板&#xff0c;总能在角落里发现一个不起眼的组合——电容串联着电阻&#xff0c;安静地躺在交流电源入口处。这个看似简单的电路&#xff0c;正是让220V高压电安全降为5V低压的关键角色。去年…

作者头像 李华
网站建设 2026/7/16 3:08:49

【需求工程】 建模功能和流程(L3)

EU 3.4.4 建模功能和流程&#xff08;L3&#xff09; 动态模型&#xff1a;活动模型&#xff08;Activity Model&#xff09; 和 过程模型&#xff08;Process Model&#xff09;。 很多初学者会把它们混为一谈&#xff0c;但 IREB 告诉你&#xff1a;两者关注的“粒度”和“视…

作者头像 李华