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


    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],因为出售股票永远比持有股票时所持有的现金要多。

    代码:

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

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

    空间优化代码:

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

    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])。

    代码:

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

  • 相关阅读:
    SWT/ANR问题--Dump时间过长导致的SWT
    关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?
    电脑上出现应用程序无法正常启动0xc0000142的解决方法
    【数据结构】链表--双链表
    【MySQL】MySQL建表与常见类型设计陷阱(MySQL专栏启动)
    技术应用:使用Spring Boot、MyBatis Plus和Dynamic DataSource实现多数据源
    ADO连接Access的前期绑定方法实例(下)
    json数据和文件操作
    React基础-React中发送Ajax请求以及Mock数据
    lc--655:输出二叉树
  • 原文地址:https://blog.csdn.net/weixin_45613481/article/details/128112001