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

刷题找工作《买卖股票问题》一文通解相关推荐

  1. 《LeetCode刷题》—121. 买卖股票的最佳时机

    <LeetCode刷题>-121. 买卖股票的最佳时机 一.题目内容 原题连接:https://leetcode.cn/problems/best-time-to-buy-and-sell ...

  2. 【力扣刷题】121.买卖股票的最好时机(python)

    题目简述 给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格. 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票.设计 ...

  3. 力扣刷题day42|121买卖股票的最佳时机、122买卖股票的最佳时机II

    文章目录 121. 买卖股票的最佳时机 贪心思路 动态规划思路 动态规划五部曲 122. 买卖股票的最佳时机II 贪心思路 动态规划思路 动态规划五部曲 121. 买卖股票的最佳时机 力扣题目链接 给 ...

  4. Leetcode刷题笔记 714. 买卖股票的最佳时机含手续费

    714. 买卖股票的最佳时机含手续费 时间:2020年12月17日 知识点:动态规划 题目链接:https://leetcode-cn.com/problems/best-time-to-buy-an ...

  5. [LeetCode刷题笔记]714 - 买卖股票的最佳时机含手续费(C++/Python3/Java/动态规划/贪心)

    一.题目描述 给定一个整数数组 prices 和 整数 fee ,其中 prices[i] 表示第 i 天的股票价格,fee 代表了交易股票的手续费用. 你可以无限次地完成交易,但是你每笔交易都需要付 ...

  6. 【2021/5/17 刷题笔记】买卖股票的最佳时机与动态规划

    文章目录 买卖股票的最佳时机 [题目] [我的方法] 执行结果: 动态规划算法 1.状态定义 2.设置数组边界值 3.推导状态转换方程. 参考代码 执行结果: 复杂度分析: 时间复杂度 空间复杂度 * ...

  7. JavaScript实现找出买卖股票的最大利润算法(附完整源码)

    JavaScript实现找出买卖股票的最大利润算法(附完整源码) dpBestTimeToBuySellStocks.js完整源代码 dpBestTimeToBuySellStocks.test.js ...

  8. 【LeetCode每日一题】——714.买卖股票的最佳时机含手续费

    文章目录 一[题目类别] 二[题目难度] 三[题目编号] 四[题目描述] 五[题目示例] 六[解题思路] 七[题目提示] 八[时间频度] 九[代码实现] 十[提交结果] 一[题目类别] 贪心算法 二[ ...

  9. [Leetcode][第309题][JAVA][最佳买卖股票时机含冷冻期][动态规划][压缩空间]

    [问题描述][中等] [解答思路] 1. 动态规划 动态规划流程 第 1 步:设计状态 f[i]表示第 i 天结束之后的「累计最大收益」 第 2 步:状态转移方程 f[i][0]=max(f[i−1] ...

最新文章

  1. 利用virtualenv和pip构建虚环境并安装配置推送客户端
  2. 结构体序列为JSON
  3. 【视频课】模型部署课程更新!ncnn框架快速实践!
  4. 限制IIS站点的内存,避免级联影响
  5. iOS开发之CALayer
  6. python论文摘要_python新玩法:用python进行文章摘要拿取,只需要一行代码
  7. Unitest框架的使用(四)HTMLTestRunner输出测试报告
  8. 【免费下载】2022年1月热门报告盘点(附热门报告列表及下载链接)
  9. 如何正确的使用WinRAR,去除错误弹框
  10. java色_JavaSE是什么
  11. 辐射校正(传感器定标+大气校正)
  12. Pycharm 编辑器取消中间分割线
  13. 如何在微信中下载APP
  14. 绝对值对应c语言表达式,c语言绝对值函数?
  15. iOS开发打包上传报错ERROR ITMS-90096
  16. 有一个已经排好序的数组。现输入一个数,要求按原来的规律将它插入数组中。(c语言)
  17. 用python 编写一个简单的游戏
  18. AE影视后期特效制作深入剖析AE表达…
  19. Ae 内置效果控件(合集)
  20. 【cordova学习笔记01】h5打包成apk

热门文章

  1. 不同银行的银行卡正则校验
  2. 软件安全分析与应用概述
  3. 2016/2/18 html 图片热点,网页划区,拼接,表单
  4. 不用微博SDK,直接使用 新浪微博 分享链接进行分享
  5. 【论文】军事理论课程论文
  6. 五指棋人机大战之ai篇
  7. Windows防火墙的原理及其作用
  8. 机器学习的数学基础 矩阵论与概率论
  9. spring security_一文肝爆Spring安全框架Spring Security
  10. 微信公众平台开发(PHP)(五) 天气预报功能开发