股票交易问题全拿下,一扫光
上来直接最难的,后面都是毛毛雨
问题一:买卖股票的最佳时机IV(leetcode188)
问题二:最大可交易次数不限(leetcode122)
问题三:最大交易次数为1(leetcode121)
问题四:最大交易次数为2(leetcode123)
问题五:买卖股票最佳时间含手续费(leetcode714)
问题六:最佳股票买卖时机含冷冻期(leetcode309)
问题一:买卖股票的最佳时机IV(leetcode188)
问题描述:
给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iv
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
大体思路:
二维数组dp0[i][j]表示在第i天,最大可交易次数为j时不持有股票的最大收益;
同理dp1[i][j]表示在第天,最大可交易次数为j时持有股票的最大收益。i从0到最大天数,j从0到k。
dp0[i][j] = max(dp0[i - 1][j], dp1[i - 1][j] + prices[i])
dp1[i][j] = max(dp1[i - 1][j], dp0[i - 1][j - 1] - prices[i])
第一个式子:当天没有股票有两种可能,要么前一天就没持有股票;要么为前一天持有股票,当天卖了。
第二个式子:当天持有股票有两种可能,要么前一天就持有股票,或者前一天没持有股票,当天买入了。
注:这里需要注意的是第二个式子中,第二种情况下的前一天的最大可交易次数为j-1而不为j,这是由于买入的次数要小于最大买入次数,假设为dp0[i - 1][j] 他可能在i-1天之前已经进行过j次交易了,在第i天坑定不能再买入了。
传递函数有了,下面描述其的初值。
我们从传递函数发现,当前值总是与其正上方的值和左上角的值有关,因此只要对dp0和dp1的第一列第一行初始化即可。
dp0的第一列和第一行均为0,首先第一列j=0,由于最大可交易次数为0,那坑定不能买了为0,第一行i= 0,由于在第1天,不持有股票只有一种可能就是没有买所以为0。
dp1的第一列,j= 0最大可交易次数为0,但是还要持有,这是不可能实现的,因此为非法状态统统设为负无穷;第一行(除第一个元素)i = 0,可交易次数大于0了,在第1天想持有股票,只能买第一天的,因此统统设为 -1 * prices[0]。
实现代码如下:
class Solution {public int maxProfit(int k, int[] prices) {if(k == 0 || prices.length <= 1){return 0;}if(k > prices.length / 2){return maxProfit(prices);}int[][] dp0 = new int[prices.length][k + 1];int[][] dp1 = new int[prices.length][k + 1];/* dp0[i][0] 和 dp0[0][j] 均为0*/for(int i = 0; i < prices.length; i++){dp1[i][0] = Integer.MIN_VALUE;}for(int j = 1; j < k + 1; j++){dp1[0][j] = -1 * prices[0];}for(int i = 1; i < prices.length; i++){for(int j = 1; j < k + 1; j++){dp0[i][j] = Math.max(dp0[i - 1][j], dp1[i - 1][j] + prices[i]);dp1[i][j] = Math.max(dp1[i - 1][j], dp0[i - 1][j - 1] - prices[i]);}}return dp0[prices.length - 1][k];}public int maxProfit(int[] prices) {if(prices.length <= 1){return 0;}int[] dp0 = new int[prices.length];int[] dp1 = new int[prices.length];dp1[0] = -1 * prices[0];for(int i = 1; i < dp0.length; i++){dp0[i] = Math.max(dp0[i - 1], dp1[i - 1] + prices[i]);dp1[i] = Math.max(dp1[i - 1], dp0[i - 1] - prices[i]);}return dp0[dp0.length - 1];}
}
由于k可能很大,当k > n / 2时问题就会转化为不用考虑最大交易次数的情况,可以认为最大交易次数为无穷。后面的代码下一节将会分析。
问题二:最大可交易次数不限(leetcode122)
该问题是问题一中k = 无穷的特例,此时 k = k - 1,因此转移函数变为
dp0[i] = max(dp0[i - 1], dp1[i - 1] + prices[i])
dp1[i] = max(dp1[i - 1], dp0[i - 1] - prices[i])
问题由二维dp转化为一维dp
初值为:d0[0] = 0,没买肯定是0啊, d1[0] = -prices[0],买了肯定是- prices[0]。
实现代码如下:
public int maxProfit(int[] prices) {if(prices.length <= 1){return 0;}int[] dp0 = new int[prices.length];int[] dp1 = new int[prices.length];dp1[0] = -1 * prices[0];for(int i = 1; i < dp0.length; i++){dp0[i] = Math.max(dp0[i - 1], dp1[i - 1] + prices[i]);dp1[i] = Math.max(dp1[i - 1], dp0[i - 1] - prices[i]);}return dp0[dp0.length - 1];}
问题三:最大交易次数为1(leetcode121)
dp0[i][j] = max(dp0[i - 1][j], dp1[i - 1][j] + prices[i])
dp1[i][j] = max(dp1[i - 1][j], dp0[i - 1][j - 1] - prices[i])
将上式中的j换成1,得到如下:
dp0[i][1] = max(dp0[i - 1][1], dp1[i - 1][1] + prices[i])
dp1[i][1] = max(dp1[i - 1][1], dp0[i - 1][0] - prices[i])
由于dp0[i - 1][0] = 0,所以最终化简后的转移方程为:
dp0[i]= max(dp0[i - 1], dp1[i - 1]+ prices[i])
dp1[i]= max(dp1[i - 1], 0 - prices[i])
初值:dp0[0] = 0, dp1[0] = -prices[0]
该结果也可以使用自然语言理解,当天不持有的有两种情况,或者前一天就不持有,或者前一天持有当天卖出去了;当天持有的两种情况为:前一天就持有,或者前一天不会持有,当天买了。由于只能买一次,前一天不持有说明之前也没进行过交易,因此前一天不持有的最大收益为0.
实现代码如下:
public int maxProfit(int[] prices) {if(prices.length <= 1){return 0;}int[] dp0 = new int[prices.length];// dp0[i] i天不持有股票的最大利润int[] dp1 = new int[prices.length]; // 持有股票的最大利润 dp0[0] = 0;dp1[0] = -1 * prices[0];for(int i = 1; i < prices.length; i++){dp0[i] = Math.max(dp0[i - 1], dp1[i - 1] + prices[i]);dp1[i] = Math.max(dp1[i - 1], 0 - prices[i]);}return dp0[dp0.length - 1];}
当然由于只交易一次,因此还可以很多其他办法解决,比如可以使用贪心的策略,找到当前点之前最小的元素,即在前面那个位置买,在当前点卖。由于本文主要将dp,这里就不多加赘述了。
问题四:最大交易次数为2(leetcode123)
这问题没啥说的,就令k=2咯,直接搞。
代码如下:
public int maxProfit(int[] prices) {if(prices.length <= 1){return 0;}int K = 2;int[][] dp0 = new int[prices.length][K + 1];int[][] dp1 = new int[prices.length][K + 1]; // dp0[0][k] 和 dp0[i][0] 均为0for(int i = 0; i < prices.length; i++){ // 第一列 最大允许交易次数为0 还要持有 定为非法dp1[i][0] = Integer.MIN_VALUE;}for(int k = 1; k <= K; k++){ //第一行dp1[0][k] = -1 * prices[0];}for(int i = 1; i < prices.length; i++){for(int k = 1; k <= K; k++){dp0[i][k] = Math.max(dp0[i - 1][k], dp1[i - 1][k] + prices[i]);dp1[i][k] = Math.max(dp1[i - 1][k], dp0[i - 1][k - 1] - prices[i]);}}return dp0[prices.length - 1][K];}
问题五:买卖股票最佳时间含手续费(leetcode714)
问题描述:
给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-transaction-fee
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
大体思路:
直接在k=无穷上改就行,由于每笔交易都含手续费,因此在卖的时候加上手续费就行,转移方程如下:
dp0[i] = max(dp0[i - 1], dp1[i - 1] + prices[i] - fee)
dp1[i] = max(dp1[i - 1], dp0[i - 1] - prices[i])
初值 dp0[0] = 0, dp1[0] = - prices[0]
代码如下:
public int maxProfit(int[] prices, int fee) {if(prices.length <= 1){return 0;}int[] dp0 = new int[prices.length];int[] dp1 = new int[prices.length];dp1[0] = -1 * prices[0];for(int i = 1; i < prices.length; i++){dp0[i] = Math.max(dp0[i - 1], dp1[i - 1] + prices[i] - fee);dp1[i] = Math.max(dp1[i - 1], dp0[i - 1] - prices[i]);}return dp0[dp0.length - 1];}
问题六:最佳股票买卖时机含冷冻期(leetcode309)
问题描述:
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
示例:
输入: [1,2,3,0,2]
输出: 3
解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
大体思路:
由于当天卖出股票后第二天不能直接买入,也就是说只有前天没持有,昨天没持有,今天才可以进行买入。传递函数如下:
dp0[i] = max(dp0[i - 1], dp1[i - 1] + prices[i])
dp1[i] = max(dp1[i - 1], dp0[i - 2] - prices[i])
由于前天没有持有,昨天也没有持有,今天买入之前的收益是等于前天的收益的。因此为dp0[i - 2] - prices[i]
由于用到i- 2,初值除了赋i= 0,还应对 i = 1赋值。
dp0[0] = 0;
dp1[0] = 0 - prices[0];
dp0[1] = Math.max(dp0[0], dp1[0] + prices[1]);
dp1[1] = Math.max(dp1[0], dp0[0] - prices[1]);// 由于-1时坑定没卖出,因此为dp0[0] - prices[1]。
实现代码如下:
public int maxProfit(int[] prices) {// return dfs(prices, 0, 0, 0, 0);if(prices.length <= 1){return 0;}int[] dp0 = new int[prices.length]; //dp0[i] 为i天不持有股票的最大收益int[] dp1 = new int[prices.length]; //dp0[0] = 0;dp1[0] = 0 - prices[0];dp0[1] = Math.max(dp0[0], dp1[0] + prices[1]);dp1[1] = Math.max(dp1[0], dp0[0] - prices[1]);for(int i = 2; i < prices.length; i++){dp0[i] = Math.max(dp0[i - 1], dp1[i - 1] + prices[i]);dp1[i] = Math.max(dp1[i - 1], dp0[i - 2] - prices[i]);}return dp0[prices.length - 1];}
股票交易问题全拿下,一扫光相关推荐
- 看完946页“JAVA高级架构面试必问”,金九银十社招全拿下
前言 我本科毕业后在老东家干了两年多,老东家算是一家"小公司"(毕竟这年头没有 BAT 或 TMD 的 title 都不好意思报出身),毕业这两年多我也没有在大厂待过,因此找坑的时 ...
- 946页“JAVA高级架构必问面试精华”,金九银十社招全拿下
前言 我本科毕业后在老东家干了两年多,老东家算是一家"小公司"(毕竟这年头没有 BAT 或 TMD 的 title 都不好意思报出身),毕业这两年多我也没有在大厂待过,因此找坑的时 ...
- 清华朱军团队开源UniDiffuser:首个基于Transformer的多模态扩散大模型!文图互生、改写全拿下!...
点击下方卡片,关注"CVer"公众号 AI/CV重磅干货,第一时间送达 点击进入->[多模态和扩散模型]微信技术交流群 转载自:机器之心 该论文提出了一个为多 模态设计的概率 ...
- 老牌名校助理教授给出8个建议
点击上方"视学算法",选择加"星标"或"置顶" 重磅干货,第一时间送达 作者丨子豪 来源丨量子位 编辑丨极市平台 学术写作,绝对算得上高校学 ...
- 热门专业没那么难,文科生打开统计学的正确方式!
六月,初夏. 高考结束,毕业季到来.准大学生纠结选什么专业,毕业生迈进就业大军,不论什么身份,大家都在思考着同一件事情--当下什么能力最热门? 想要得到答案很简单,打开任意一款求职软件,热门岗位的职位 ...
- 简单点,让论文写作简单点,老牌名校助理教授给出8个建议
子豪 发自 凹非寺 量子位 报道 | 公众号 QbitAI 学术写作,绝对算得上高校学生最为头痛的事之一,无论是论文,还是研究报告.说明文件-- 对理工科学生来说,更是难上加难--方案.实验全拿下,一 ...
- 辣眼睛:程序员这样过儿童节
需要智慧 戏精程序员 不能浪得虚名 "我觉得这个不错,宅男都爱,兄弟,你的公仔借我们一用." "这东西你哪里淘来的?不愧是震桌之宝" 搜刮了整栋大楼之后 阿里云 ...
- 高盛发布区块链报告:从理论到实践(中文版)
投资组合经理之摘要 现在硅谷和华尔街都为了区块链着迷,逐渐忘记了作为其技术源头的比特币.但对其潜在应用的讨论仍十分抽象和深奥.焦点在于使用分布式账本建立去中心化市场,并削弱现有中间商的控制权. 但区块 ...
- 前端面试——初(H)入(T)江(M)湖(L)
前言 如果觉得文章对您有帮助记得给个 Star,你的 star 是我动力的源泉.github 地址 正所谓面试如考试,考试如战场.战场上必将刀光剑影. 阅文档,刷试题,只求简历能入围 会面试官,戏 H ...
最新文章
- 高级特性(4)- 数据库编程
- linux kernel 2.6.36 编译升级
- 最长回文子串python_最长回文子串(Python)
- 被关起来日子的流水帐
- 熊猫的python小课账号_学习python中的pandas有没有好的教程推荐?
- 线性代数:矩阵乘向量-学习笔记
- iPhone 13临近发布,富士康需要在9月底前再招聘20万名工人
- [AST实战]从零开始写一个wepy转VUE的工具
- Kibana将语言设置为中文
- 读 疯狂的程序员 有感
- PD快充协议JD6606S资料
- 如果矩阵中存在字符用C语言,面试中常见的数据结构与算法题整理,想当架构师,数据结构与算法不过关可不行(数组+字符串,共60题)...
- call方法 java_漫谈JS中的call和apply方法
- 相见恨晚的5个资源网站 影视音乐资源随你看
- 数字化转型对企业的意义
- linux请求超时 ping_linux下ping命令使用详解
- java字符串同构_Java同构代码
- 每日一录20220816—01
- 如何从WinXP镜像中提取超级终端程序?
- 导航装备便携式综合测试工装