Best Time to Buy and Sell Stock

原题链接Best Time to Buy and Sell Stock

给定一个价格序列prices,其中prices[i]代表第i天商品的价格,商家需要在某一天买入,然后在之后的某一天出售,计算可以获得的最大利润

本质就是计算prices[i]−prices[j]prices[i] - prices[j]的最大值,要求i>ji > j

假设已经直到最后结果的最大值位置i(prices[i]),只需要减去最小值即可,那么就需要直到最小值是多少,本题中当从左到右遍历时,完全可以随着遍历进度的增加记录最小值

代码如下

class Solution {
public:int maxProfit(vector<int>& prices) {if(prices.empty())  return 0;/* 记录目前位置找到的最小值 */int minPrices = prices[0];/* 记录最大差值 */int maxProfit = 0;for(int i = 1; i < prices.size(); ++i){/* 以prices[i]作为最大值,尝试计算差值 */maxProfit = std::max(maxProfit, prices[i] - minPrices);/* 尝试更新最小值 */minPrices = std::min(minPrices, prices[i]);}return maxProfit;}
};

当然也可以遍历两次求解,第一次对于每个位置的值,计算它的右侧比它大的最大值,第二次对于每个位置,计算右侧的最大值与自己的差,更新最大差值,求出结果

代码如下

class Solution {
public:int maxProfit(vector<int>& prices) {int n = prices.size();vector<int> dp(n + 1, 0);/* 计算prices[i]右侧的最大值,包括自己 */for(int i = n - 1; i >= 0; --i)dp[i] = std::max(dp[i + 1], prices[i]);int maxProfit = 0;/* 右侧最大值 - 自身 = 最大差值 */for(int i = 0; i < n; ++i)maxProfit = std::max(maxProfit, dp[i] - prices[i]);return maxProfit;}
};

Best Time to Buy and Sell Stock II

原题链接Best Time to Buy and Sell Stock II

要求和上面一样,不过这次可以进行多次交易,即买,卖,买,卖,买,卖…,其中买卖不能在同一天进行

这样就不能像上面那样只求一次了,其实仔细想一下,序列无非三种排列

  • 递增,假设A<B<C<DA
  • 递减,假设A>B>C>DA > B > C > D
  • 无序,假设A<B>C<DA C

对于递增序列,最大的差值就是D−AD - A,因为(D−A)=(D−C)+(C−B)+(B−A)>(D−C)+(B−A)(D - A) = (D - C) + (C - B) + (B - A) > (D - C) + (B - A)

对于递减序列,为0

对于无序序列,总可以找到若干个递增序列,就上面的例子而言最大差值为(B−A)+(D−C)(B - A) + (D - C),而实际上也可以写成(D−C)+max(C−B,0)+(B−A)(D - C) + max(C - B, 0) + (B - A),和递增序列的形式是一样的

所以只要依次计算prices[i]−prices[i−1]prices[i] - prices[i - 1]即可

代码如下

class Solution {
public:int maxProfit(vector<int>& prices) {int maxProfit = 0;for(int i = 1; i < prices.size(); ++i)maxProfit += std::max(prices[i] - prices[i - 1], 0);return maxProfit;}
};

Best Time to Buy and Sell Stock III

原题链接Best Time to Buy and Sell Stock III

同样是买卖问题,本题要求最多可以完成两次交易,计算最大利润

利用动态规划,对动态规划数组states[i][j]有如下规定

  • states[][0]代表0次买,0次卖的利润
  • states[][1]代表一次买,0次卖的利润(显然是负数)
  • states[][2]代表一次买,一次卖的利润
  • states[][3]代表两次买,一次卖的利润
  • states[][4]代表两次买,两次卖的利润

而states,规定它是二维数组,states[0]代表当前的利润,states[1]代表执行完本次操作后的利润,那么有

  • states[1][1] = std::max(states[0][1], states[0][0] - prices[i]),表示买入商品prices[i],那么利润就是0次买0次卖的利润减商品价格,当然需要和1次买0次卖比较,选择较大的那个
  • states[1][2] = std::max(states[0][2], states[0][1] + prices[i]),表示卖出商品prices[i],那么利润就是1次买0次卖的利润加商品价格,当然需要和1次买1次卖比较,选择较大的那个
  • …同理

初始状态,另1次买0次卖的利润为INT_MIN,两次买一次卖的利润为INT_INT,是为了让max选择后者,因为初始状态没有买入任何商品

代码如下

class Solution {
public:int maxProfit(vector<int>& prices) {vector<vector<int>> states(2, vector<int>(2 * 2 + 1, 0));states[0][0] = 0;for(int i = 1; i < 2 * 2 + 1; i += 2){states[0][i] = INT_MIN;states[0][i + 1] = 0;}int cur = 0, next = 1;for(int i = 0; i < prices.size(); ++i){states[next][1] = std::max(states[cur][1], states[cur][0] - prices[i]);states[next][2] = std::max(states[cur][2], states[cur][1] + prices[i]);states[next][3] = std::max(states[cur][3], states[cur][2] - prices[i]);states[next][4] = std::max(states[cur][4], states[cur][3] + prices[i]);/* next变为当前 */std::swap(next, cur);}return states[cur][2 * 2];}
};

Best Time to Buy and Sell Stock IV

原题链接Best Time to Buy and Sell Stock IV

和上面一样,要求最多可以进行k次交易

只需要将上面的两次交易换成k次即可

class Solution {
public:int maxProfit(int k, vector<int>& prices) {vector<vector<int>> states(2, vector<int>(2 * k + 1, 0));  states[0][0] = 0;for(int i = 1; i < 2 * k + 1; i += 2){states[0][i] = INT_MIN;states[0][i + 1] = 0;}int cur = 0, next = 1;for(int i = 1; i < prices.size(); ++i){/* 把两次变为k次,就需要放在循环里了 */for(int j = 1; j < 2 * k + 1; j += 2){states[next][j] = std::max(states[cur][j], states[cur][j - 1] - prices[i]);states[next][j + 1] = std::max(states[cur][j + 1], states[cur][j] + prices[i]);}std::swap(next, cur);}return states[cur][2 * k];}
};

不过这样可能内存溢出,因为如果k很大,申请的内存很容易溢出,解决方法是当k很大时采用其他方法。什么时候k算大呢,就是k次交易可以涉及到每一天,也就是k >= prices.size() / 2,此时就可以转换为没有交易次数限制的问题

代码如下

class Solution {
public:int maxProfit(int k, vector<int>& prices) {/* 如果k很大,采用其他方式 */if(k >= prices.size() / 2)return quickSolver(prices);vector<vector<int>> states(2, vector<int>(2 * k + 1, 0));  for(int i = 1; i < 2 * k + 1; i += 2){states[0][i] = INT_MIN;states[0][i + 1] = 0;}int cur = 0, next = 1;for(int i = 0; i < prices.size(); ++i){/* 把两次变为k次,就需要放在循环里了 */for(int j = 1; j < 2 * k + 1; j += 2){states[next][j] = std::max(states[cur][j], states[cur][j - 1] - prices[i]);states[next][j + 1] = std::max(states[cur][j + 1], states[cur][j] + prices[i]);}std::swap(next, cur);}return states[cur][2 * k];}
private:/* 没有交易次数限制,直接遍历,见第二题 */int quickSolver(vector<int>& prices){int profit = 0;for(int i = 1; i < prices.size(); ++i)profit += std::max(prices[i] - prices[i - 1], 0);return profit;}
};

第一道题的第一种解法比较好,直接遍历一遍同时记录最小值和最大差值,同时也没有额外的空间使用

第二道题不太容易理解,其实对于序列无非递增,递减,无序三种可能,分别观察一下即可

第三第四题主要以动态规划为主

每天一道LeetCode-----买卖商品问题,计算最大利润,分别有一次交易,两次交易,多次交易的情况相关推荐

  1. 每日一道 LeetCode (16):求 x 的平方根

    每天 3 分钟,走上算法的逆袭之路. 前文合集 每日一道 LeetCode 前文合集 代码仓库 GitHub: https://github.com/meteor1993/LeetCode Gitee ...

  2. leetcode买卖股票问题(思路、方法、code)

    一文解决Leetcode买卖股票问题 对于前3个问题,均采用了比较巧妙的解法.由于第4个问题具有非常强的泛型,因此采用了DP,第4个问题的dp如果理解的话,实际上只需要稍加修改状态便可以用该dp思路应 ...

  3. LeetCode买卖股票之一:基本套路(122)

    欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 关于<LeetCode买卖股票>系列 在L ...

  4. LeetCode买卖股票的最佳时机系列总结

    LeetCode买卖股票的最佳时机系列总结 此类动态规划从二维动规理解后优化到一维动规,部分题目还可以用到贪心. 目录: 121 买卖股票的最佳时机1 122 买卖股票的最佳时机2 123 买卖股票的 ...

  5. leetcode 买卖股票系列题目总结

    总结:买卖股票系列题目 1.买卖股票的最佳时机(简单) 121. 买卖股票的最佳时机 难度简单1093 给定一个数组,它的第 i 个元素是一支给定股票第 i 天的价格. 如果你最多只允许完成一笔交易( ...

  6. 一天一道LeetCode(61-90)

    一天一道LeetCode(61-90) 文章目录 一天一道LeetCode(61-90) 61.旋转链表 62.不同路径 63.不同路径 II 64.最小路径和 65.有效数字(未解决) 66.加一 ...

  7. 每日一道 LeetCode (42):旋转数组

    每天 3 分钟,走上算法的逆袭之路. 前文合集 每日一道 LeetCode 前文合集 代码仓库 GitHub: https://github.com/meteor1993/LeetCode Gitee ...

  8. 【一天一道Leetcode】基本计算器的延伸问题

    本篇推文共计2000个字,阅读时间约3分钟. 01 题目描述 题目描述: 给你一个字符串表达式s,请你实现一个基本计算器来计算并返回它的值. 整数除法仅保留整数部分. 示例: 输入:s = " ...

  9. LeetCode 买卖股票的最佳时机 - 超详细讲解系列题

    1.分析 使用通用方法,也即动态规划DP (1)LeetCode 121. 买卖股票的最佳时机 class Solution {public int maxProfit(int[] prices) { ...

最新文章

  1. java程序分为哪两大类_JAVA程序基础(第1-2章分类)复习-1
  2. 子数组最大值设计02
  3. 第14章 结构和其他数据形式 14.12 typedef 简介
  4. LoadCursor 加载不同的鼠标光标
  5. spring容器bean的作用域 spring容器是否是单例的一些问题
  6. jpa 托管_java – jpa非托管实体
  7. “让天下没有难开的店”,宣言来自无人车公司AutoX
  8. clion打开时如何不自动重新打开上一次的项目
  9. 编程程序_PLC编程代码PLC程序设计公司
  10. 哪些命令可以关闭计算机 poweroff,虚拟机常用命令
  11. hlgoj 1766 Cubing
  12. 2022年P气瓶充装考试试题及答案
  13. leetcode1月31日-2月6日做题笔记
  14. 21.Rust的面向对象特征
  15. Arduino UNO的原理图
  16. Fibonacci数列 Huffman树
  17. 港科资讯 | 香港科技大学校歌正式发布!
  18. 一文看懂嵌入式总线技术,ISA总线最流行?
  19. 专业课-数据结构(回文判断实验)
  20. MATLAB EXPO 2018演讲实录丨MathWorks美国总部全球产品市场经理赵志宏

热门文章

  1. Java黑皮书课后题第7章:7.15(消除重复)使用下面的方法头编写方法,消除数组中重复出现的值。编写一个测试程序,读取10个数,调用该方法,并显示以一个空格分隔的不同数字
  2. html 编辑xml,编辑XML\HTML时取消浏览“amp”
  3. php编译freetds,Linux 下 PHP 5.2.x 连接 SQL Server 数据库 FreeTDS 配置笔记
  4. 海量数据随机抽样问题(蓄水池问题)
  5. win10系统下安装mysql
  6. Git 系列(二):初步了解 Git
  7. ASP.NET 打包多CSS或JS文件以加快页面加载速度的Handler
  8. openSUSE设置为路由服务器
  9. [系统安全] 四十六.Powershell恶意代码检测系列 (1)Powershell基础入门及管道和变量的用法
  10. [Pyhon疫情大数据分析] 三.新闻信息抓取及词云可视化、文本聚类和LDA主题模型文本挖掘