leetcode买卖股票问题(思路、方法、code)
一文解决Leetcode买卖股票问题
对于前3个问题,均采用了比较巧妙的解法。由于第4个问题具有非常强的泛型,因此采用了DP,第4个问题的dp如果理解的话,实际上只需要稍加修改状态便可以用该dp思路应用于所有的6个题中。在后两个问题便是基于该思路用dp解决的。
文章目录
- 一文解决Leetcode买卖股票问题
- [121. 买卖股票的最佳时机](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock/)
- [122. 买卖股票的最佳时机 II](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-ii/)
- [123. 买卖股票的最佳时机 III](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/)
- [188. 买卖股票的最佳时机 IV](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv/)
- [714. 买卖股票的最佳时机含手续费](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee/)
- [309. 最佳买卖股票时机含冷冻期](https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/)
121. 买卖股票的最佳时机
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
如果你最多只允许完成一笔交易(即买入和卖出一支股票一次),设计一个算法来计算你所能获取的最大利润。
示例 1:
输入: [7,1,5,3,6,4]
输出: 5
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。示例 2:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
分析:对于每一天而言,如果当天卖股票,则当天能够获得的最大利润就是当天的股票价格减去之前的最小值,也就是历史最低值。 故动态记录历史最低值和最大利润即可,遍历一遍数组。
class Solution {public:int maxProfit(vector<int>& prices) {if(prices.size()==0||prices.size()==1) return 0;int min_price=prices[0]; //记录之前的最小值,也就是历史最低点int max_profit=0; //记录最大利润for(int i=0;i<prices.size();i++){max_profit=max(prices[i]-min_price,max_profit);if(prices[i]<min_price) //出现新的最低点min_price=prices[i];}return max_profit;}
};
122. 买卖股票的最佳时机 II
给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你可以尽可能地完成更多的交易(多次买卖一支股票)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [7,1,5,3,6,4]
输出: 7
解释: 在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6-3 = 3 。示例 2:
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。示例 3:
输入: [7,6,4,3,1]
输出: 0
解释: 在这种情况下, 没有交易完成, 所以最大利润为 0。
class Solution {public:int maxProfit(vector<int>& prices) {int profit=0;for(int i=0;i<prices.size()-1;i++){if(prices[i]<prices[i+1]) //第二天高于今天价格profit+=prices[i+1]-prices[i];}return profit;}
};
123. 买卖股票的最佳时机 III
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [3,3,5,0,0,3,1,4]
输出: 6
解释: 在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。示例 2:
输入: [1,2,3,4,5]
输出: 4
解释: 在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。 示例 3:
输入: [7,6,4,3,1]
输出: 0
解释: 在这个情况下, 没有交易完成, 所以最大利润为 0。
正向遍历时,是已知前面的最小值,因此要让利润最大就是尽可能找最大值
f i r s t [ i ] = m a x ( f i r s t [ i − 1 ] , p r i c e s [ i ] − m i n _ p r i c e ) first[i]=max(first[i-1],prices[i]-min\_price) first[i]=max(first[i−1],prices[i]−min_price)
反向遍历时,是已知后面的最大值,因此要让利润最大就是尽可能找最小值
l a s t [ i ] = m a x ( l a s t [ i + 1 ] , m a x _ p r i c e − p r i c e s [ i ] ) last[i]=max(last[i+1],max\_price-prices[i]) last[i]=max(last[i+1],max_price−prices[i])
时间复杂度为O(n),空间复杂度为O(n)
class Solution {public:int maxProfit(vector<int>& prices) {if(prices.size()==0||prices.size()==1) return 0;vector<int> first(prices.size());first[0]=0;vector<int> last(prices.size());last[prices.size()-1]=0;//求first[]时正着求,已经最小值,找后面尽可能大的值int min_price=prices[0];for(int i=1;i<prices.size();i++){first[i]=max(first[i-1],prices[i]-min_price);min_price=min(min_price,prices[i]);}//求last[]时候要倒着求,是已知最大值,找前面尽可能小的值int max_price=prices[prices.size()-1];for(int i=prices.size()-2;i>=0;i--){last[i]=max(last[i+1],max_price-prices[i]);max_price=max(max_price,prices[i]);}int max_profit=0;for(int i=0;i<prices.size();i++)max_profit=max(first[i]+last[i],max_profit);return max_profit;}
};
188. 买卖股票的最佳时机 IV
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
示例 1:
输入: [2,4,1], k = 2
输出: 2
解释: 在第 1 天 (股票价格 = 2) 的时候买入,在第 2 天 (股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2 。示例 2:
输入: [3,2,6,5,0,3], k = 2
输出: 7
解释: 在第 2 天 (股票价格 = 2) 的时候买入,在第 3 天 (股票价格 = 6) 的时候卖出, 这笔交易所能获得利润 = 6-2 = 4 。随后,在第 5 天 (股票价格 = 0) 的时候买入,在第 6 天 (股票价格 = 3) 的时候卖出, 这笔交易所能获得利润 = 3-0 = 3 。
分析:显然,这个问题,是前面三个问题的高度泛化。处理前面三个问题时,用到了很多技巧与规律,但显然,处理该问题必须得有一个比较泛化的思路。(该题的解法很明显可以应用于之前三个题)
- d p [ i ] [ 0 ] [ 0 ] = 0 dp[i][0][0]=0 dp[i][0][0]=0 :没有持股票,也没有进行交易,故利润为0
- d p [ i ] [ 0 ] [ k ] = m a x ( d p [ i − 1 ] [ 1 ] [ k − 1 ] + p r i c e s [ i ] , d p [ i − 1 ] [ 0 ] [ k − 1 ] ) dp[i][0][k]=max(dp[i-1][1][k-1]+prices[i],dp[i-1][0][k-1]) dp[i][0][k]=max(dp[i−1][1][k−1]+prices[i],dp[i−1][0][k−1]): 没有持有股票,已经卖出了k次股票,那当前情况的原因可能是:昨天也是未持股且卖出了k次,昨天持股了并且今天卖出了
- d p [ i ] [ 1 ] [ k ] = m a x ( d p [ i − 1 ] [ 0 ] [ k ] − p r i c e s [ i ] , d p [ i − 1 ] [ 1 ] [ k ] ) dp[i][1][k]=max(dp[i-1][0][k]-prices[i],dp[i-1][1][k]) dp[i][1][k]=max(dp[i−1][0][k]−prices[i],dp[i−1][1][k]) :持有股票,进行过k次交易,可能原因是:昨天没有持股且已经进行了k次交易然后今天买入了股票,昨天持股且没有进行交易
- d p [ i ] [ 1 ] [ m a x _ k ] = − i n f dp[i][1][max\_k]=-inf dp[i][1][max_k]=−inf:持有股票且已经进行了足够的交易,此情况不存在
- 最后的结果,应该是在最后一天时,没有持有股票的情况下,进行过 0~max_k 次交易的利润最大值(因为在最后一天,未持有股票一定比持有股票有着更大的收益)
class Solution {public:int maxProfit(int max_k, vector<int>& prices) {if(prices.size()==0||prices.size()==1) return 0;if(max_k>prices.size()/2) return maxProfit2(prices);//相当于无限交易int length=prices.size();int dp[length][2][max_k+1];//进行部分初始化,主要将第一天的情况进行初始化dp[0][1][0]=-prices[0]; //第一天买入了股票dp[0][0][0]=0;for(int i=1;i<length;i++) {dp[i][0][0]=0;//没有进行过交易且未持股dp[i][1][0]=max(dp[i-1][1][0],-prices[i]);//没有进行过交易且持股}for(int k=1;k<=max_k;k++){ //第一天不存在卖出的情况dp[0][1][k]=INT_MIN/2;dp[0][0][k]=INT_MIN/2;}for(int i=1;i<length;i++)for(int k=1;k<=max_k;k++){//对所有情况用状态转移方程求解dp[i][0][k]=max(dp[i-1][1][k-1]+prices[i],dp[i-1][0][k]);dp[i][1][k]=max(dp[i-1][0][k]-prices[i],dp[i-1][1][k]);}int result=0;for(int k=0;k<=max_k;k++)result=max(dp[length-1][0][k],result);return result;}int maxProfit2(vector<int>& prices) //贪心求解无限制k问题{int profit=0;for(int i=0;i<prices.size()-1;i++){if(prices[i]<prices[i+1]) //第二天高于今天价格profit+=prices[i+1]-prices[i];}return profit;}
};
714. 买卖股票的最佳时机含手续费
给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
示例 1:
输入: prices = [1, 3, 2, 8, 4, 9], fee = 2
输出: 8
解释: 能够达到的最大利润:
在此处买入 prices[0] = 1
在此处卖出 prices[3] = 8
在此处买入 prices[4] = 4
在此处卖出 prices[5] = 9
总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.
- d p [ 0 ] [ 0 ] = 0 dp[0][0]=0 dp[0][0]=0 , d p [ 0 ] [ 1 ] = − p r i c e s [ 0 ] − f e e dp[0][1]=-prices[0]-fee dp[0][1]=−prices[0]−fee 第一天未持有股票则利润为0,第一天持有股票说明第一天买入则利润为 当前价格加上手续费 的相反数
- d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] + p r i c e s [ i ] ) dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]) dp[i][0]=max(dp[i−1][0],dp[i−1][1]+prices[i]) :没有持有股票,说明可能是昨天没有持有股票今天也没有买入,也可能昨天持有股票且今天卖出了
- d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] − p r i c e s [ i ] − f e e ) dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]-fee) dp[i][1]=max(dp[i−1][1],dp[i−1][0]−prices[i]−fee) :持有股票,说明可能是昨天持有股票且今天没有卖出,也可能是昨天没有持有股票且今天买入了
- 思路如此,但是实现时候,发现每次状态转移只与之前的两个状态相关,因此实际上用四个变量就可以存储dp数组的有效内容
//最初的dp思路
class Solution {public:int maxProfit(vector<int>& prices, int fee) {if(prices.size()==0||prices.size()==1)return 0;int length=prices.size();int dp[length][2];dp[0][0]=0;dp[0][1]=-prices[0]-fee;for(int i=1;i<length;i++){dp[i][0]=max(dp[i-1][0],dp[i-1][1]+prices[i]);dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i]-fee);}return dp[length-1][0];}
};
//优化空间的dp思路
class Solution {public:int maxProfit(vector<int>& prices, int fee) {if(prices.size()==0||prices.size()==1)return 0;int length=prices.size();int pre_0=0,pre_1=-prices[0]-fee; //表示昨天的未持股和持股int ex_0=pre_0,ex_1=pre_1; //表示当天的未持股和持股for(int i=1;i<length;i++){ex_0=max(pre_0,pre_1+prices[i]);ex_1=max(pre_1,pre_0-prices[i]-fee);pre_0=ex_0;pre_1=ex_1;}return ex_0;}
};
309. 最佳买卖股票时机含冷冻期
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
分析:该题是在之前第二个问题基础上增加了冷冻期,增加了冷冻期将使得最初的想法实现时有些问题,因此也采用dp的方法进行状态转移。
- 初始化第1天: d p [ 0 ] [ 0 ] = 0 , d p [ 0 ] [ 1 ] = − p r i c e s [ 0 ] dp[0][0]=0,dp[0][1]=-prices[0] dp[0][0]=0,dp[0][1]=−prices[0]
- 初始化第2天: d p [ 1 ] [ 0 ] = m a x ( d p [ 0 ] [ 0 ] , d p [ 0 ] [ 1 ] + p r i c e s [ 1 ] ) , d p [ 1 ] [ 1 ] = m a x ( d p [ 0 ] [ 1 ] , − p r i c e s [ 1 ] ) dp[1][0]=max(dp[0][0],dp[0][1]+prices[1]),dp[1][1]=max(dp[0][1],-prices[1]) dp[1][0]=max(dp[0][0],dp[0][1]+prices[1]),dp[1][1]=max(dp[0][1],−prices[1])
- d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 1 ] + p r i c e s [ i ] , d p [ i − 1 ] [ 0 ] ) dp[i][0]=max(dp[i-1][1]+prices[i],dp[i-1][0]) dp[i][0]=max(dp[i−1][1]+prices[i],dp[i−1][0]) 第i天没有持股,可能是昨天持股但今天卖了,也可能昨天未持股
- d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 2 ] [ 0 ] − p r i c e s [ i ] ) dp[i][1]=max(dp[i-1][1],dp[i-2][0]-prices[i]) dp[i][1]=max(dp[i−1][1],dp[i−2][0]−prices[i]) 第i天持股,可能是昨天没有持股,也可能是前天持股了卖了,然后今天买入的
class Solution {public:int maxProfit(vector<int>& prices) {if(prices.size()==0||prices.size()==1)return 0;int length=prices.size();int dp[length][2];//初始化dp[0][0]=0;dp[0][1]=-prices[0];dp[1][0]=max(dp[0][0],dp[0][1]+prices[1]);dp[1][1]=max(dp[0][1],-prices[1]);for(int i=2;i<length;i++){dp[i][0]=max(dp[i-1][1]+prices[i],dp[i-1][0]);dp[i][1]=max(dp[i-1][1],dp[i-2][0]-prices[i]);}return dp[length-1][0];}
};
leetcode买卖股票问题(思路、方法、code)相关推荐
- LeetCode买卖股票之一:基本套路(122)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<LeetCode买卖股票>系列 在L ...
- LeetCode买卖股票的最佳时机系列总结
LeetCode买卖股票的最佳时机系列总结 此类动态规划从二维动规理解后优化到一维动规,部分题目还可以用到贪心. 目录: 121 买卖股票的最佳时机1 122 买卖股票的最佳时机2 123 买卖股票的 ...
- leetcode 买卖股票问题
leetcode 买卖股票问题 lc121 买卖股票最佳时机 lc122 买卖股票最佳时机II lc123. 买卖股票的最佳时机 III lc188. 买卖股票的最佳时机 IV lc121 买卖股票最 ...
- leetcode 买卖股票系列题目总结
总结:买卖股票系列题目 1.买卖股票的最佳时机(简单) 121. 买卖股票的最佳时机 难度简单1093 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 如果你最多只允许完成一笔交易( ...
- LeetCode 买卖股票的最佳时机 - 超详细讲解系列题
1.分析 使用通用方法,也即动态规划DP (1)LeetCode 121. 买卖股票的最佳时机 class Solution {public int maxProfit(int[] prices) { ...
- LeetCode 买卖股票的最佳时机 6道题1个解法总结
一个方法解决6道买卖股票题:来自LeetCode题解 一.穷举框架 利用「状态」进行穷举.我们具体到每一天,看看总共有几种可能的「状态」,再找出每个「状态」对应的「选择」.我们要穷举所有「状态」,穷举 ...
- [Leetcode] 买卖股票合集(动态规划)
写完这套题,再搞一台时光机,财务自由不是梦(Doge) ================================== 相关题目链接 121 买卖股票的最佳时机 122 买卖股票的最佳时机 II ...
- LeetCode买卖股票问题集合(六种股票问题)
一.买卖股票的最佳时机 (LeetCode 121) 简单的动态规划问题,只能完成一次买卖,定义二维 dp[i] [] 数组,dp [i] [0]表示没有股票的状态,dp [i] [1]表示持有股票的 ...
- 【leetcode买卖股票系列问题】多次买卖/手续费/冻结期
一.目录 一.目录 二.股票系列问题 1.买卖股票的最佳时机(121题) 1.1.题目 1.2.思路 1.3.代码实现(1种) 2.买卖股票的最佳时机II(122题) 2.1.题目 2.2.思路 2. ...
最新文章
- poj1002(map的使用)
- Sqlserver2014在Windows中打开Configuration Manager
- 新手学C语言会踩到什么样的坑?
- python data frame_Python dataframer包_程序模块 - PyPI - Python中文网
- laravel 任务队列_laravel队列-让守护进程处理耗时任务
- 派单o2o全开源版 v11.6.0 全新UI版小程序模块
- python数字图像处理(5):图像的绘制
- centos 解决“不在 sudoers 文件中。此事将被报告“的问题
- [Linux]使用宝塔面板做负载均衡时遇到的问题和解决办法
- 详解:MySQL数据库的权限管理和运维实操
- 显卡dos测试软件,A+N卡测试说明_早期显卡DOS版本
- 军事指挥系统时间同步解决方案
- 那些年我们听过的法则
- Windows Internet Information Services(IIS) 与 inetpub 文件夹
- python+ opencv实现摄像头实时人脸识别并实现汉字标框
- ps拾取颜色设置文字颜色
- [渝粤教育] 江西财经职业学院 成本核算与管理 参考 资料
- android系统自动休眠代码流程,一种基于Android系统下的可控休眠方法及系统与流程...
- 最大公约数和最小公倍数(GCD LCM)—简写版
- July博客第十二章参考学习
热门文章
- 无线通信技术学习笔记——概述
- PHPer是草根吗?
- 免费空间主机是什么?怎么申请免费空间主机
- 阿里腾讯还做不到,这30%的市场,雷军眼光更胜一筹!
- SpringBoot2的Shiro最简配置(两个文件)
- DirectX12初始化一——DX::ThrowIfFailed使用
- 90%以上的基础设施由OpenStack管理和提供的CERN,现在如何了?
- 激活试用60天office2007的步骤
- ExecuteThread: '5' for queue: 'weblogic.kernel.Default (self-tuning)' has been busy for 653 secon
- Android 设置属性动画AnimatorSet设置pause无效问题