刷题找工作《买卖股票问题》一文通解
NO.121 买卖股票的最佳时机 简单 、NO.122 买卖股票的最佳时机II 简单 、NO.123 买卖股票的最佳时机III 困难 、NO.188 买卖股票的最佳时机IV 困难
NO.121 买卖股票的最佳时机 简单
思路一:暴力法 没什么好说的,双重循环计算所有元素两两组合相减的结果,取最大。
public int maxProfit(int[] prices) {int maxProfit=0;for (int i = 0; i < prices.length - 1; i++) {for (int j = i+1; j < prices.length; j++) {maxProfit=Math.max(maxProfit,prices[j]-prices[i]);}}return maxProfit;
}
时间复杂度:O(n^2)
思路二:优化暴力法到一次遍历 买卖股票从第二天开始我们每天都会"后悔":后悔没有在之前的最低点进行买入,只有这样我们的收益才会最大化。
由此可见,我们想要当天利益最大化,只需要在过去的某个最低点买入股票就好。所以我们只需要记录曾经出现过的最低点就好。
public int maxProfit(int[] prices) {int minPoint=Integer.MAX_VALUE,maxProfit=0;for (int i = 0; i < prices.length; i++) {//记录曾出现过最低点minPoint=Math.min(prices[i],minPoint);//当日-曾经的最低maxProfit=Math.max(maxProfit,prices[i]-minPoint);}return maxProfit;
}
时间复杂度:O(n)
从NO.121题不难看出:买股票的最佳时机是曾经!股市有风险,入股需谨慎!(狗头)
单纯的解答本题是比较简单的,但是买卖股票可以算作是一个系列的经典问题,在leetcode上就有本题一系列的变种问题:买卖股票的最佳时机、买卖股票的最佳时机II、买卖股票的最佳时机III、买卖股票的最佳时机IV、买卖股票的最佳时机含冷冻期、买卖股票的最佳时机含手续费。
虽然这些题有难有易,但是既然是一类问题,就有这一些通用的方法。
这六个问题都是由第四个问题简化变种而来的,第四题相较于本题多了一个参数k,限制只能进行k次交易;第一题也就是本题是只进行一次交易,相当于 k = 1;第二题是不限交易次数,相当于 k = +infinity(正无穷);第三题是只进行 2 次交易,相当于 k = 2;剩下两道也是不限次数,但是加了交易「冷冻期」和「手续费」的额外条件,其实就是第二题的变种。
NO.122 买卖股票的最佳时机II 简单
思路一:贪心算法 姊妹题NO.121,区别在于NO.121题只允许交易一次(一次买入、一次卖出),而本题没有交易次数的限制。
所以想到贪心算法,因为我们是"上帝视角"知道"未来股价",所以只要赚钱我们每天都进行交易。
所谓赚钱就是:“明天i+1股价”-“今天i股价”>0,这种情况今天就买入;否则就是赔钱或者不赚钱的情况,不进行交易。
public int maxProfit(int[] prices) {if (prices == null || prices.length == 0) return 0;int Profit = 0;for (int i = 0; i < prices.length - 1; i++) {//今天i买,明天i+1赚钱。就今天买入,明天卖。int sub = prices[i + 1] - prices[i];if (sub > 0) {Profit += sub;}}return Profit;
}
时间复杂度:O(n)
思路二:动态规划 贪心算法已经很好地解决了这个问题,但是我们还是要带入一下DP解法,为后序的姊妹题NO.122买卖股票的最佳时机III、以及等等很多其他的XXX买卖股票问题都是基于本题进行变化的,无非是在本题的基础上增加更多的限制条件。
dp[i][j]的含义:i表示第i天,j表示持股状态(0表示不持股,1表示持股)。dp[i][j]整体就表示第i天持股/不持股时手里的钱。
初始化:dp[0][0]=0,刚开始不赔不赚;dp[0][1]= -prices[0],只支出了。
状态转移:dp[i][0]=Max(dp[i-1][0],dp[i-1][1]+prices[i])
,即第i天不持股时手里钱最多为MAX(i-1天不持股i天继续不持股,i-1天持股+i天以当日价格卖掉股票);
同理dp[i][1]=Max(dp[i-1][0]-prices[i],dp[i-1][1])
,即第i天持股时手里钱最多为MAX(i-1天不持股-i天以当日价格买入股票,i-1天持股i天继续持股)。
public int maxProfit(int[] prices) {if (prices == null || prices.length < 2) return 0;//初始化int[][] dp = new int[prices.length][2];dp[0][0] = 0;dp[0][1] -= prices[0];//状态转移for (int i = 1; i < prices.length; i++) {dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] + prices[i]);dp[i][1] = Math.max(dp[i - 1][0] - prices[i], dp[i - 1][1]);}//最后一天一定是不持股的return dp[prices.length - 1][0];
}
时间复杂度:O(n)
NO.123 买卖股票的最佳时机III 困难
思路一:动态规划 NO.121是只能买卖一次股票,NO.122是任意买卖股票,而本题是只能买卖股票两次。
相较于前两题的状态,本题又增加了一个交易次数的状态k。
dp[i][j][k]的含义:第i天的利润,j表示持股状态(0不持股,1持股),k交易次数(卖出次数0~2)。所以每天有六种状态,思路就是从每天的六种状态中找到利润最大的。
初始化:dp[0][0][0]=dp[0][0][1]=dp[0][0][2]=0
,啥也没干;dp[0][1][0]=dp[0][1][1]=dp[0][1][2]=-prices[0]
,第一天持股只有支出。
状态转移:dp[i][0][0]=dp[i-1][0][0]
,第i天不持股交易次数0,第i-1天一定未持股未交易,维持现状;
dp[i][0][1]=MAX(dp[i-1][0][1],dp[i-1][1][0]+prices[i])
,第i天不持股1次交易,维持第i-1天的状态,或者第i-1天持股未交易第i天卖出。
dp[i][0][2]=MAX(dp[i-1][0][2],dp[i-1][1][1]+prices[i])
,第i天不持股2次交易,维持第i-1天的状态,或者第i-1天持股1次交易第i天卖出。
dp[i][1][0]=MAX(dp[i-1][1][0],dp[i-1][0][0]-prices[i])
,第i天持股未交易,维持第i-1天的状态,或者第i-1天不持股未交易第i天买入。
dp[i][1][1]=MAX(dp[i-1][1][1],dp[i-1][0][1]-prices[i])
,第i天持股1次交易,维持第i-1天的状态,或者第i-1天不持股1次交易第i天买入。
dp[i][1][2]=dp[i][1][2]
,第i天持股2次交易,已经到达交易限制,但是手中还持股,不需要考虑一定不能利润最大化。
最终的结果一定是在不持股的三种状态中进行比较。
public int maxProfit(int[] prices) {if (prices == null || prices.length < 2) return 0;//初始化int[][][] dp = new int[prices.length][2][3];dp[0][0][0] = dp[0][0][1] = dp[0][0][2] = 0;dp[0][1][0] = dp[0][1][1] = dp[0][1][2] = -prices[0];//状态转移for (int i = 1; i < prices.length; i++) {//六种状态dp[i][0][0] = dp[i - 1][0][0];dp[i][0][1] = Math.max(dp[i - 1][0][1], dp[i - 1][1][0] + prices[i]);dp[i][0][2] = Math.max(dp[i - 1][0][2], dp[i - 1][1][1] + prices[i]);dp[i][1][0] = Math.max(dp[i - 1][1][0], dp[i - 1][0][0] - prices[i]);dp[i][1][1] = Math.max(dp[i - 1][1][1], dp[i - 1][0][1] - prices[i]);dp[i][1][2] = dp[i - 1][1][2];}//最大利润一定是不持股的三种状态之一。return Math.max(dp[prices.length - 1][0][2],Math.max(dp[prices.length - 1][0][1], dp[prices.length - 1][0][0]));
}
时间复杂度:O(n) 空间O(n)虽然是三维数组,但2和3是常数。
NO.188 买卖股票的最佳时机IV 困难
思路一:动态规划 在上一题的基础上两次交易,变味了 k 次交易。但是需要考虑的状态,仍然是三个,第 i 天、j 持股状态、k 进行过的交易次数。
虽然 k 从上一题的常量 2 变为了本题的变量,但是 dp 数组的含义不变。但是本题如果使用三维数组会因为 k 值过大,导致内存超出。
所以采用两个一维数组 dpi0[k+1] 和 dpi1[k+1] 表示第 i 天持股(1)或不持股(0)时,不同交易次数下的利润。(上一题也可以采用这个方法,进行空间优化)
实现上,由于本题 k 不是上一题中的常量 2 ,无法手动写死每种情况,所以采用一个 for 循环即可。
public int maxProfit(int k, int[] prices) {if (k<=0||prices.length<1)return 0;//最多只能交易 prices.lenght/2 次if (k>prices.length/2) k = prices.length/2;//初始化int[] dpi0 = new int[k+1];int[] dpi1 = new int[k+1];for (int j = 1; j < k + 1; j++) {dpi1[j] = -prices[0];}//状态转移for (int i = 1; i < prices.length; i++) {for (int j = k; j >= 1; j--) {//第i天不持股 = Max(第i-1天不持股,第i-1天持股+第i天出售)dpi0[j] = Math.max(dpi0[j],dpi1[j]+prices[i]);//第i天持股 = Max(第i-1天持股,第i-1天不持股-第i天买入)dpi1[j] = Math.max(dpi1[j],dpi0[j-1]-prices[i]);}}return dpi0[k];
}
时间复杂度:O(n*k) n 共n天
空间复杂度:O(k)
本人菜鸟,有错误请告知,感激不尽!
更多题解和学习记录博客:博客、github
刷题找工作《买卖股票问题》一文通解相关推荐
- 《LeetCode刷题》—121. 买卖股票的最佳时机
<LeetCode刷题>-121. 买卖股票的最佳时机 一.题目内容 原题连接:https://leetcode.cn/problems/best-time-to-buy-and-sell ...
- 【力扣刷题】121.买卖股票的最好时机(python)
题目简述 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格. 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票.设计 ...
- 力扣刷题day42|121买卖股票的最佳时机、122买卖股票的最佳时机II
文章目录 121. 买卖股票的最佳时机 贪心思路 动态规划思路 动态规划五部曲 122. 买卖股票的最佳时机II 贪心思路 动态规划思路 动态规划五部曲 121. 买卖股票的最佳时机 力扣题目链接 给 ...
- Leetcode刷题笔记 714. 买卖股票的最佳时机含手续费
714. 买卖股票的最佳时机含手续费 时间:2020年12月17日 知识点:动态规划 题目链接:https://leetcode-cn.com/problems/best-time-to-buy-an ...
- [LeetCode刷题笔记]714 - 买卖股票的最佳时机含手续费(C++/Python3/Java/动态规划/贪心)
一.题目描述 给定一个整数数组 prices 和 整数 fee ,其中 prices[i] 表示第 i 天的股票价格,fee 代表了交易股票的手续费用. 你可以无限次地完成交易,但是你每笔交易都需要付 ...
- 【2021/5/17 刷题笔记】买卖股票的最佳时机与动态规划
文章目录 买卖股票的最佳时机 [题目] [我的方法] 执行结果: 动态规划算法 1.状态定义 2.设置数组边界值 3.推导状态转换方程. 参考代码 执行结果: 复杂度分析: 时间复杂度 空间复杂度 * ...
- JavaScript实现找出买卖股票的最大利润算法(附完整源码)
JavaScript实现找出买卖股票的最大利润算法(附完整源码) dpBestTimeToBuySellStocks.js完整源代码 dpBestTimeToBuySellStocks.test.js ...
- 【LeetCode每日一题】——714.买卖股票的最佳时机含手续费
文章目录 一[题目类别] 二[题目难度] 三[题目编号] 四[题目描述] 五[题目示例] 六[解题思路] 七[题目提示] 八[时间频度] 九[代码实现] 十[提交结果] 一[题目类别] 贪心算法 二[ ...
- [Leetcode][第309题][JAVA][最佳买卖股票时机含冷冻期][动态规划][压缩空间]
[问题描述][中等] [解答思路] 1. 动态规划 动态规划流程 第 1 步:设计状态 f[i]表示第 i 天结束之后的「累计最大收益」 第 2 步:状态转移方程 f[i][0]=max(f[i−1] ...
最新文章
- 利用virtualenv和pip构建虚环境并安装配置推送客户端
- 结构体序列为JSON
- 【视频课】模型部署课程更新!ncnn框架快速实践!
- 限制IIS站点的内存,避免级联影响
- iOS开发之CALayer
- python论文摘要_python新玩法:用python进行文章摘要拿取,只需要一行代码
- Unitest框架的使用(四)HTMLTestRunner输出测试报告
- 【免费下载】2022年1月热门报告盘点(附热门报告列表及下载链接)
- 如何正确的使用WinRAR,去除错误弹框
- java色_JavaSE是什么
- 辐射校正(传感器定标+大气校正)
- Pycharm 编辑器取消中间分割线
- 如何在微信中下载APP
- 绝对值对应c语言表达式,c语言绝对值函数?
- iOS开发打包上传报错ERROR ITMS-90096
- 有一个已经排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。(c语言)
- 用python 编写一个简单的游戏
- AE影视后期特效制作深入剖析AE表达…
- Ae 内置效果控件(合集)
- 【cordova学习笔记01】h5打包成apk