LeetCode上的各种股票最大收益

LeetCode上的各种股票最大收益

对于力扣平台上的股票类型的题目:

  • 121 买卖股票的最佳时机

  • 122 买卖股票的最佳时机 II

  • 123 买卖股票的最佳时机 III

  • 124 买卖股票的最佳时机 IV

  • 309 最佳买卖股票时机含冷冻期

  • 714 买卖股票的最佳时机含手续费

  • 剑指 Offer 63. 股票的最大利润

关键是要仔细分析题意,将每天结束后可能存在的状态列出来,并考虑当天与前一天的可能存在的状态转移的关系。另外要注意初始化空间复杂度的优化

121. 买卖股票的最佳时机

dp数组含义

本题在某一天共可能有两种状态:

  • 持有股票
  • 不持有股票

我们构造的 dp 数组的规模为 2×n2\times n2×n,在 C++ 中,即为:vector<<vevtor<int>> dp(prices.size(), vector<int> (2, 0));

  • dp[i][0]dp[i][0]dp[i][0] 表示在第 iii结束后,在持有股票的状态下的最大收益
  • dp[i][1]dp[i][1]dp[i][1] 表示在第 iii结束后,在不持有股票的状态下的最大收益

递推公式

  • 对于第 iii 天持有股票时的收益,即 dp[i][0]dp[i][0]dp[i][0],可能由以下情况推导而来:

    • i−1i-1i1 天是也是持有股票的,即当日未进行任何操作:dp[i−1][0]dp[i-1][0]dp[i1][0]

    • i−1i-1i1 天是未持有股票的,即当日购买了股票,由于我们只能进行一次股票买卖操作,因此在购买股票之前的 dp[i−1][1]dp[i-1][1]dp[i1][1] 一定是 0,因此应当减去当日股票价格:0−prices[i]0-prices[i]0prices[i]

    应当取最大值,从而 dp[i][0]=max(dp[i−1][0],−prices[i])dp[i][0]=max(dp[i-1][0],-prices[i])dp[i][0]=max(dp[i1][0],prices[i])

  • 对于第 iii 天未持有股票时的收益,即 dp[i][1]dp[i][1]dp[i][1],可能由以下情况推导而来:

    • i−1i-1i1 天是是持有股票的,即当日将股票卖出,应当 dp[i−1][0]dp[i-1][0]dp[i1][0] 加上当日股票价格:dp[i−1][0]+prices[i]dp[i-1][0]+prices[i]dp[i1][0]+prices[i]
    • i−1i-1i1 天是未持有股票的,即当日无操作:prices[i−1][1]prices[i-1][1]prices[i1][1]

    应当取最大值,从而 dp[i][1]=max(dp[i−1][1],dp[i−1][0]+prices[i])dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i])dp[i][1]=max(dp[i1][1],dp[i1][0]+prices[i])

初始化

dp 数组中所有项需在 dp[0][0]dp[0][0]dp[0][0]dp[0][1]dp[0][1]dp[0][1] 确定的情况下得到。

  • dp[0][0]dp[0][0]dp[0][0] 表示第一天持有股票,即第一天购入,应为 −prices[0]-prices[0]prices[0]
  • dp[0][1]dp[0][1]dp[0][1] 表示第一天未持有股票,应为 0

遍历顺序

从前向后

代码

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

空间优化

很明显,第 iii 天的情况只依赖于前一天的情况,而与再前面的情况没有关系,因此,我们没有必要维护一整个 dp 数组,而是维护常数变量即可,优化后:

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

另一种做法

class Solution {
public:int maxProfit(vector<int>& prices) {int ans = 0, prevMin = INT_MAX;for (int n: prices) {ans = max(ans, n - prevMin);prevMin = min(prevMin, n);}return ans;}
};

122. 买卖股票的最佳时机 II

本题与121 题的唯一区别在于可以多次买卖股票,但要注意同时只能持有一只股票

dp数组含义

  • dp[i][0]dp[i][0]dp[i][0] 表示在第 iii 天结束后,持有股票时的最大收益
  • dp[i][1]dp[i][1]dp[i][1] 表示在第 iii 天结束后,不持有股票时的最大收益

递推公式

注意由于这里与上一题的唯一区别在于允许多次股票买卖,因此递推公式与上面的四种情况基本相同,唯一一点在于由于我们可以进行多次买卖,所以在某次购买股票之前的未持有股票的收益不一定是 0 了(我们可能在这次操作之前已经通过几次操作收获了一些利润)。

即对于 dp[i][0]dp[i][0]dp[i][0] 在前一日不持有股票的情况从 0−prices[i]0-prices[i]0prices[i] 变为了 dp[i−1][1]−prices[i]dp[i-1][1]-prices[i]dp[i1][1]prices[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])dp[i][0]=max(dp[i1][0],dp[i1][1]prices[i])

初始化遍历顺序与前题类似。

代码

class Solution {
public:int maxProfit(vector<int>& prices) {int lens = prices.size();vector<vector<int>> dp(lens, vector<int> (2));dp[0][0] = -prices[0], dp[0][1] = 0;for (int i=1; i<lens; ++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]);}return dp[lens-1][1];}
};

注意代码中的唯一区别在于:

dp[i][0] = max(dp[i-1][0], dp[i-1][1] - prices[i]);

原因上面已经解释过。

空间优化的实现与上面也类似,这里就不贴了。

另一种写法

本题有另一种做法,由于我们可以进行无限次交易且当日即可以买入又可以卖出,所以考虑:

[7, 1, 5, 6] 第二天买入,第四天卖出,收益最大(6-1),所以一般人可能会想,怎么判断不是第三天就卖出了呢? 这里就把问题复杂化了,根据题目的意思,当天卖出以后,当天还可以买入,所以其实可以第三天卖出,第三天买入,第四天又卖出((5-1)+ (6-5) === 6 - 1)。所以算法可以直接简化为只要今天比昨天大,就卖出

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

123. 买卖股票的最佳时机 III

本题相较于前面两题要复杂不少,关键是最多两次交易,即有可能可以是 0,1,2 次交易,我们需要列举处理的情况多了不少。

dp数组的定义

本题中,我们一共要考虑每一天的五种状态:

  • 尚未进行操作
  • 第一次买入后
  • 第一次卖出后
  • 第二次买入后
  • 第二次卖出后

注意我们这里要强调各个状态是 买入/卖出 后 ,即不一定是当日买入/卖出,可能是 i−1i-1i1i−2i-2i2 …日进行的操作,都归为该状态。并且,注意到,这些状态是有序的,即一定是一次经历到的。

由此,我们 dp 数组的含义为:dp[i][j]dp[i][j]dp[i][j] 表示,第 iii 天处于状态 jjj 时的最大收益。

递推公式

  • 对于第 iii 日结束后。处于第一次买入后状态,即 dp[i][1]dp[i][1]dp[i][1],可能由以下情况推导而来:

    • 前面已经买入,当日未进行操作:dp[i−1][1]dp[i-1][1]dp[i1][1]
    • 当日买入:dp[i−1][0]−prices[i]dp[i-1][0]-prices[i]dp[i1][0]prices[i]

    取最大值,则有:dp[i][1]=max(dp[i−1][1],dp[i−1][0]−prices[i])dp[i][1]=max(dp[i-1][1],dp[i-1][0]-prices[i])dp[i][1]=max(dp[i1][1],dp[i1][0]prices[i])

  • 对于第 iii 日处于第一次卖出后,即 dp[i][2]dp[i][2]dp[i][2],可能由以下情况推导而来:

    • 前面已经卖出,当日未进行任何操作:dp[i−1][2]dp[i-1][2]dp[i1][2]
    • 当日卖出:dp[i−1][1]+prices[i]dp[i-1][1]+prices[i]dp[i1][1]+prices[i]

    则:dp[i][2]=max(dp[i−1][2],dp[i−1][1]+prices[i])dp[i][2]=max(dp[i-1][2],dp[i-1][1]+prices[i])dp[i][2]=max(dp[i1][2],dp[i1][1]+prices[i])

  • 同理,dp[i][3]=max(dp[i−1][3],dp[i−1][2]−prices[i])dp[i][3]=max(dp[i-1][3],dp[i-1][2]-prices[i])dp[i][3]=max(dp[i1][3],dp[i1][2]prices[i])

  • 同理,dp[i][4]=max(dp[i−1][4],dp[i−1][3]+prices[i])dp[i][4]=max(dp[i-1][4],dp[i-1][3]+prices[i])dp[i][4]=max(dp[i1][4],dp[i1][3]+prices[i])

代码

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

优化代码

class Solution {
public:int maxProfit(vector<int>& prices) {int fstBuy = INT_MIN, fstSell = 0;int secBuy = INT_MIN, secSell = 0;for (int p: prices) {fstBuy = max(fstBuy, -p);fstSell = max(fstSell, fstBuy + p);secBuy = max(secBuy, fstSell - p);secSell = max(secSell, secBuy + p);}return secSell;}
};

188. 买卖股票的最佳时机 IV

上一题的一般化,分好奇偶即可:

class Solution {
public:int maxProfit(int k, vector<int>& prices) {if (prices.empty()) return 0;int lens = prices.size();int wide = 2 * k + 1;vector<vector<int>> dp(lens, vector<int> (wide, 0));for (int j=0; j<wide; ++j) if (j % 2 == 1) dp[0][j] = -prices[0];for (int i=1; i<lens; ++i) {dp[i][0] = dp[i-1][0];for (int j=1; j<wide; ++j) {if (j % 2 == 1) dp[i][j] = max(dp[i-1][j], dp[i-1][j-1] - prices[i]);else if (j % 2 == 0) dp[i][j] = max(dp[i-1][j], dp[i-1][j-1] + prices[i]);}}return dp[lens - 1][wide - 1];}
};

309. 最佳买卖股票时机含冷冻期

dp数组含义

本题中每天可能的状态有三种:

  • 持有股票
  • 不持有股票,今天卖出,后一天为冷冻期
  • 不持有股票,非今天卖出,后一天不为冷冻期

dp[i][j]dp[i][j]dp[i][j] 表示第 iii 天结束后,在第 jjj 中状态下的最大收益

递推公式

  • 当日结束后为持有股票状态时,即 dp[i][0]dp[i][0]dp[i][0] ,可能由以下情况推导而来:

    • 当日买入股票,今天不能是冷冻期, dp[i−1][2]−prices[i]dp[i-1][2]-prices[i]dp[i1][2]prices[i]
    • 之前就已经买入了股票,当日未进行操作:dp[i−1][0]dp[i-1][0]dp[i1][0]

    则,dp[i][0]=max(dp[i−1][0],dp[i−1][2]−prices[i])dp[i][0]=max(dp[i-1][0],dp[i-1][2]-prices[i])dp[i][0]=max(dp[i1][0],dp[i1][2]prices[i])

  • 当日卖出,即 dp[i][1]dp[i][1]dp[i][1]

    • 今天卖出,前一天必为持股状态,dp[i−1][0]+prices[i]dp[i-1][0]+prices[i]dp[i1][0]+prices[i]

    则,dp[i][1]=dp[i−1][0]+prices[i]dp[i][1]=dp[i-1][0]+prices[i]dp[i][1]=dp[i1][0]+prices[i]

  • 非当日卖出,即 dp[i][2]dp[i][2]dp[i][2],可能由以下情况推导而来:

    • 前一日卖出,今日冷冻期,dp[i−1][1]dp[i-1][1]dp[i1][1]
    • 非前一日卖出,今日非冷冻期:dp[i−1][2]dp[i-1][2]dp[i1][2]

    dp[i][2]=max(dp[i−1][1],dp[i−1][2])dp[i][2]=max(dp[i-1][1],dp[i-1][2])dp[i][2]=max(dp[i1][1],dp[i1][2])

初始化:除了第一天就买股票 dp[0][0]=−prices[0]dp[0][0]=-prices[0]dp[0][0]=prices[0] 外全 0。

遍历顺序:从前到后即可。

代码

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

714. 买卖股票的最佳时机含手续费

就加个手续费,和 122 区别不大。

dp数组含义

本题中每一天结束后有两种状态:持有股票和不持有股票

  • dp[i][0]dp[i][0]dp[i][0] 表示第 iii 天结束后处于持股状态时的最大收益
  • dp[i][1]dp[i][1]dp[i][1] 表示第 iii 天结束后处于未持股状态时的最大收益

递推公式

  • 对于第 iii 天结束后,处于持股状态,即 dp[i][0]dp[i][0]dp[i][0],可能由两种状态推导得到:

    • 前面买入,当日未进行操作:dp[i−1][0]dp[i-1][0]dp[i1][0]
    • 当日买入,并支付手续费 dp[i−1][1]−prices[i]−feedp[i-1][1]-prices[i]-feedp[i1][1]prices[i]fee

    则:dp[i][0]=max(dp[i−1][0],dp[i−1][1]−prices[i]−fee)dp[i][0]=max(dp[i-1][0],dp[i-1][1]-prices[i]-fee)dp[i][0]=max(dp[i1][0],dp[i1][1]prices[i]fee)

  • 对于第 iii 天结束后,处于未持股状态,即 dp[i][1]dp[i][1]dp[i][1],可能由两种状态推导得到:

    • 一直未买入或前面已卖出,当日未进行操作:dp[i−1][1]dp[i-1][1]dp[i1][1]
    • 当日卖:dp[i−1][0]+prices[i]dp[i-1][0]+prices[i]dp[i1][0]+prices[i]

    则:dp[i][1]=max(dp[i−1][1],dp[i−1][0]+prices[i])dp[i][1]=max(dp[i-1][1],dp[i-1][0]+prices[i])dp[i][1]=max(dp[i1][1],dp[i1][0]+prices[i])

代码

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/532521.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

建设专业化运维服务团队必要性

信息系统的生命周期涵盖&#xff1a;设计、开发、测试、部署上线、运行维护。其中&#xff0c;运行维护阶段是信息系统生命周期中的关键环节&#xff0c;其执行效果直接影响系统是否能达到预期的运行目标。为了实现这个目标&#xff0c;我们必须建立一个以业务服务为导向的专业…

docker初探

docker初探 本文旨在介绍 docker 基本的安装、常用命令和常见概念的辨析&#xff0c;方便新手入门和笔者日后查阅&#xff0c;大部分内容整理自互联网&#xff0c;原出处在文中注明。 文章目录docker初探docker安装&#xff08;mac&#xff09;版本、信息相关命令version/info…

ubuntu安装zsh、oh-my-zsh及常用配置

ubuntu安装zsh、oh-my-zsh及常用配置 目前&#xff0c;ubuntu默认的shell是bash&#xff0c;但还有一种shell&#xff0c;叫做zsh它比bash更加强大&#xff0c;功能也更加完善&#xff0c;zsh虽说功能强大&#xff0c;但是配置比较复杂导致流行度不是很高 但是好东西终究是好…

Segmentaion标签的三种表示:poly、mask、rle

Segmentaion标签的三种表示&#xff1a;poly、mask、rle 不同于图像分类这样比较简单直接的计算机视觉任务&#xff0c;图像分割任务&#xff08;又分为语义分割、实例分割、全景分割&#xff09;的标签形式稍为复杂。在分割任务中&#xff0c;我们需要在像素级上表达的是一张…

tensorboard报错:ValueError Duplicate plugins for name projector 问题的出现及解决过程

tensorboard报错&#xff1a;ValueError: Duplicate plugins for name projector 问题的出现及解决过程 记录如题问题的出现及解决过程。 报错命令及信息 笔者在终端调用 tensorboard 时&#xff1a; tensorboard --logdirruns/ --bind_all报错&#xff1a; raise ValueEr…

发布自己的Python包(Pypi)

发布自己的Python包(Pypi) 我们经常使用 Pypi 来安装包&#xff0c;但是有时候我们也想要发布自己的 Pypi 包&#xff0c;有可能我们写了一个特别牛的包&#xff0c;也有可能我们只是想使用自己常用的一些轮子&#xff0c;可能这是我们日常编码中很常用的一些轮子&#xff0c;…

Ubuntu PPA 使用指南

Ubuntu PPA 使用指南 转自&#xff1a;https://zhuanlan.zhihu.com/p/55250294 一篇涵盖了在 Ubuntu 和其他 Linux 发行版中使用 PPA 的几乎所有问题的深入的文章。 如果你一直在使用 Ubuntu 或基于 Ubuntu 的其他 Linux 发行版&#xff0c;例如 Linux Mint、Linux Lite、Zorin…

如何在 Linux 中快速地通过 HTTP 提供文件访问服务

如何在 Linux 中快速地通过 HTTP 提供文件访问服务 转自&#xff1a;https://linux.cn/article-10205-1.html 如今&#xff0c;我有很多方法来通过 Web 浏览器为局域网中的其他系统提供单个文件或整个目录的访问。我在我的 Ubuntu 测试机上测试了这些方法&#xff0c;它们如下面…

Linux apt命令

Linux apt命令及其与apt-get的关系 转自&#xff1a;https://blog.csdn.net/taotongning/article/details/82320472、https://www.runoob.com/linux/linux-comm-apt.html apt&#xff08;Advanced Packaging Tool&#xff09;是一个在 Debian 和 Ubuntu 中的 Shell 前端软件包管…

杨宏宇:腾讯多模态内容理解技术及应用

杨宏宇&#xff1a;腾讯多模态内容理解技术及应用 分享嘉宾&#xff1a;杨宇鸿 腾讯 内容理解高级工程师 编辑整理&#xff1a;吴祺尧 出品平台&#xff1a;DataFunTalk 导读&#xff1a; 搜索内容的理解贯穿了整个搜索系统。我们需要从多个粒度理解搜索内容&#xff0c;包括语…

git登录相关操作梳理

git登录相关操作梳理 本文主要基于 Linux/Mac &#xff0c;Windows下未经测试&#xff0c;不过估计差不多&#xff0c;在 git bash 内操作即可。 创建ssh key并关联github等账号 因为本地Git仓库和GitHub仓库之间的传输是通过SSH加密传输的&#xff0c;GitHub需要识别是否是…

关于mmdetection上手的几点说明

关于mmdetection上手的几点说明 官方的文档很有参考价值&#xff0c;并且也有中文版&#xff0c;应当是大家上手 mmdetection 的第一参考&#xff0c;本文是记录一些笔者在小白阶段上手 mmdetection 时的一些心得&#xff0c;这些东西没有人提&#xff0c;可能是大佬们觉得这些…

docker gpu报错Error response from daemon: could not select device driver ““ with capabilities: [[gpu]]

Docker容器中使用Nvidia GPU报错 docker: Error response from daemon: could not select device driver “” with capabilities: [[gpu]]. 问题出现 我们知道&#xff0c;想要在 docker19 及之后的版本中使用 nvidia gpu 已经不需要单独安装 nvidia-docker 了&#xff0c;这…

CUDA环境详解

CUDA环境详解 本文主要介绍 CUDA 环境&#xff0c;这一堆东西网上有很多博客介绍过了&#xff0c;我再来一篇:)&#xff0c;参考前辈们的文章&#xff0c;看能不能写的更清楚一点。读后仍有问题&#xff0c;欢迎留言交流。 CUDA APIs CUDA是由NVIDIA推出的通用并行计算架构&…

共享内存简介及docker容器的shm设置与修改

共享内存简介及docker容器的shm设置与修改 共享内存简介 共享内存指 (shared memory)在多处理器的计算机系统中&#xff0c;可以被不同中央处理器&#xff08;CPU&#xff09;访问的大容量内存。由于多个CPU需要快速访问存储器&#xff0c;这样就要对存储器进行缓存&#xff…

对Docker镜像layer的理解

对Docker镜像layer的理解 转自&#xff1a;https://blog.csdn.net/u011069294/article/details/105583522 FROM python:3.6.1-alpine RUN pip install flask CMD [“python”,“app.py”] COPY app.py /app.py上面是一个Dockerfile的例子&#xff0c;每一行都会生成一个新的l…

ssh免密登录配置方法及配置

ssh免密登录配置方法及配置 直接上步骤&#xff0c;记我们本机为机器A&#xff0c;而机器B、机器C等是我们的服务器&#xff0c;我们要配置的是A到B、C等的 ssh 免密登录。 1 在机器A上生成秘钥对 ssh-keygen会得到输出&#xff1a; Generating public/private rsa key pai…

机器学习系统:设计与实现 计算图

机器学习系统:设计与实现 计算图 转自&#xff1a;https://openmlsys.github.io/chapter_computational_graph/index.html 在上一章节中&#xff0c;我们展示了用户利用机器学习框架所编写的程序。这些用户程序包含了对于训练数据&#xff0c;模型和训练过程的定义。然而为了…

常见浮点数格式梳理

常见浮点数格式梳理 IEEE 754 标准 浮点数转换网站&#xff1a;https://www.h-schmidt.net/FloatConverter/IEEE754.html IEEE二进制浮点数算术标准&#xff0c;为许多CPU与浮点运算器所采用。这个标准定义了表示浮点数的格式&#xff08;包括负零-0&#xff09;与反常值&am…

Python拾遗1:collections、itertools和内存io

Python拾遗1&#xff1a;collections、itertools和内存io 转自&#xff1a;https://www.liaoxuefeng.com/wiki/1016959663602400 本系列旨在补充python中一些很好用但是并非常规课程主线中的知识。 collections collections是Python内建的一个集合模块&#xff0c;提供了许…