代码随想录算法训练营第四十九天|121. 买卖股票的最佳时机、122.买卖股票的最佳时机II

news/2024/8/26 9:24:33

LeetCode 121. 买卖股票的最佳时机

链接:121. 买卖股票的最佳时机

思路:

这道题目用动规写起来效率其实是不如贪心的,但是对于解类似的题目还是有帮助,重点是理解动规的过程。首先定义下标:dp[i][0]表示第i天持有股票所能得到的最大金钱,dp[i][1]表示第i天不持有股票所能得到的最大金钱。所以dp是一个二维数组,大小为prices.size() x 2。然后初始化dp,dp[0][0]表示第一天买入股票,所以dp[0][0]初始化为-prices[0],持有金额为负,因为这个时候是花钱买的股票。dp[0][1]还是0,这个时候既没有买入操作也没有卖出操作,所以是0。

然后从i=1开始遍历prices数组,确定递推公式:

  1. dp[i][0] = max(dp[i-1][0], -prices[i]):第i天持有股票有两种情况:1、第i-1天就持有股票,所能持有的最大金额为前一天持有股票时的金额dp[i-1][0]。 2、第i天买入股票,所能持有的最大金额为当天股票的价格的负数-prices[i],因为是花钱买了股票。
  2. dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i]):第i天未持有股票有两种情况:1、第i-1天就未持有股票,所能持有最大金额为前一天未持有股票的金额dp[i-1][1]。 2、第i天卖出股票,所能持有最大金额为前一天持有股票的金额dp[i-1][0],加上当天出售股票所获得的金额prices[i]。

最后返回最后一天出售股票时的金额dp[prices.size() - 1][1],因为出售股票永远比持有股票时所持有的现金要多。

代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 定义下标:dp[i][0]表示第i天持有股票所能得到的最大金钱
        // dp[i][1]表示第i天不持有股票所能得到的最大金钱
        vector<vector<int>> dp(prices.size(), vector<int>(2));
        // 第0天持有股票相当于买入第0天的股票,持有金钱相当于-prices[0]
        dp[0][0] = -prices[0];
        for (int i = 1; i < prices.size(); i++)
        { 
            // 第i天持有股票有两种情况:1、第i-1天就持有股票 2、第i天买入股票
            dp[i][0] = max(dp[i-1][0], -prices[i]);
            // 第i天未持有股票有两种情况:1、第i-1天就未持有股票 2、第i天卖出股票
            dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i]);
        }
        return dp[prices.size()-1][1];
    }
};

但其实我们可以发现,在遍历的过程中我们只用了前一天的数值dp[i-1],所以二维dp数组可以压缩成2x2大小,只记录当前天所持有的最大金额和前一天所持有的最大金额。

空间优化代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 定义下标:dp[i][0]表示第i天持有股票所能得到的最大金钱
        // dp[i][1]表示第i天不持有股票所能得到的最大金钱
        vector<vector<int>> dp(2, vector<int>(2));
        // 第0天持有股票相当于买入第0天的股票,持有金钱相当于-prices[0]
        dp[0][0] = -prices[0];
        for (int i = 1; i < prices.size(); i++)
        { 
            // 第i天持有股票有两种情况:1、第i-1天就持有股票 2、第i天买入股票
            dp[i % 2][0] = max(dp[(i - 1) % 2][0], -prices[i]);
            // 第i天未持有股票有两种情况:1、第i-1天就未持有股票 2、第i天卖出股票
            dp[i % 2][1] = max(dp[(i - 1) % 2][1], dp[(i - 1) % 2][0] + prices[i]);
        }
        return dp[(prices.size() - 1) % 2][1];
    }
};

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

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

思路:

本题涉及到多次买卖,之前也用贪心法做过,贪心法的思路为计算所有的正收入,同样也可以用动态规划的做法做出来。dp下标定义和上一题一样,dp[i][0]表示第i天持有股票所能得到的最大金钱,dp[i][1]表示第i天不持有股票所能得到的最大金钱,初始化和遍历顺序也和上题是一致的。

不同的地方在于递推公式,因为可以多次买卖,本题中所能获得的最大金额是累计的,所以在买入股票的时候,所持金额不是直接变成股票的价格的负数,而是用当前所持金额减去股票价格。当前持有金额为前一天为持有股票时的金额dp[i-1][1],所以在第i天买入股票所持有的最大金额为dp[(i - 1) % 2][1]-prices[i](采用滚动数组)。最后完整递推公式如下:

  • 持有股票时的递推公式为:dp[i % 2][0] = max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1]-prices[i])。
  • 未持有股票时的递推公式为:dp[i % 2][1] = max(dp[(i - 1) % 2][1], dp[(i - 1) % 2][0] + prices[i])。

代码:

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        // 定义下标:dp[i][0]表示第i天持有股票所能得到的最大金钱
        // dp[i][1]表示第i天不持有股票所能得到的最大金钱
        vector<vector<int>> dp(2, vector<int>(2));
        // 第0天持有股票相当于买入第0天的股票,持有金钱相当于-prices[0]
        dp[0][0] = -prices[0];
        for (int i = 1; i < prices.size(); i++)
        { 
            // 第i天持有股票有两种情况:1、第i-1天就持有股票 2、第i天买入股票
            dp[i % 2][0] = max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1]-prices[i]);
            // 第i天未持有股票有两种情况:1、第i-1天就未持有股票 2、第i天卖出股票
            dp[i % 2][1] = max(dp[(i - 1) % 2][1], dp[(i - 1) % 2][0] + prices[i]);
        }
        return dp[(prices.size() - 1) % 2][1];
    }
};


http://lihuaxi.xjx100.cn/news/295592.html

相关文章

Windows8系统下DOSBox编译、链接、执行汇编语言步骤

下载安装好DOSBox后&#xff0c;同时下载debug、link、masm程序。 &#xff08;1&#xff09;建立工作目录&#xff0c;编写汇编语言源文件&#xff0c;并将debug、link、masm程序放在同一目录下。&#xff08;下图中ass.asm是汇编语言源文件&#xff09; &#xff08;2&#x…

【学习笔记】深度学习入门:基于Python的理论与实现-误差反向传播法

CONTENTS五、误差反向传播法5.1 计算图5.2 链式法则5.3 反向传播5.4 简单层的实现5.5 激活函数层的实现5.6 Affine/Softmax层的实现5.7 误差反向传播法的实现五、误差反向传播法 5.1 计算图 先引入一个很简单的问题&#xff1a;在超市买了222个100100100元一个的苹果&#xf…

Kafka 开发架构的一些问题汇总

一、Kafka 存在哪些方面的优势 1. 多生产者 可以无缝地支持多个生产者&#xff0c;不管客户端在使用单个主题还是多个主题。 2. 多消费者 支持多个消费者从一个单独的消息流上读取数据&#xff0c;而且消费者之间互不影响。 3. 基于磁盘的数据存储 支持消费者非实时地读取…

Redis使用基础教程

本篇文章转载自&#xff1a;通俗易懂的Redis数据结构基础教程_Java程序员-张凯的博客-CSDN博客 Redis有5个基本数据结构&#xff0c;string、list、hash、set和zset。它们是日常开发中使用频率非常高应用最为广泛的数据结构&#xff0c;把这5个数据结构都吃透了&#xff0c;你…

SpringCloud_第3章_微服务保护_Sentinel

SpringCloud_第3章_微服务保护 文章目录SpringCloud_第3章_微服务保护1.初识Sentinel1.1.雪崩问题及解决方案1.1.1.雪崩问题1.1.2.超时处理1.1.3.仓壁模式1.1.4.断路器1.1.5.限流1.1.6.总结1.2.服务保护技术对比1.3.Sentinel介绍和安装1.3.1.初识Sentinel1.3.2.安装Sentinel1.4…

【Android】Fragment使用

使用Fragment 我们可以把页面结构划分成几块&#xff0c;每块使用一个Fragment来管理。这样我们可以更加方便的在运行过程中动态地更新Activity中的用户界面&#xff0c;日后迭代更新、维护也是更加方便。 Fragment并不能单独使用&#xff0c;他需要嵌套在Activity 中使用&…

程序过程分析——从编译到执行

汇编源程序 mov ax,4c00H int 21H 这两条指令可以实现程序返回的功能。 编译 使用微软的masm5.0汇编编译器,文件名为masm.exe。 在编译的过程中,我们提供了一个输入,即源程序文件。最多可以得到3个输出:目标文件(.obj)、列表文件(.Ist)、交叉引用文件(.erf),这3个输…

工程总承包系列之工程总承包合同中的优先受偿权

工程总承包系列之工程总承包合同中的优先受偿权 工程总承包模式与传统的施工总承包模式&#xff0c;存在诸多不同之处&#xff0c;而现行的建设工程法律规范体系基本上是从传统的施工总承包模式出发&#xff0c;并没有考虑工程总承包模式的适用。而且工程总承包合同其性质为何…