leetcode刷题笔记 309.最佳买卖股票时机冷冻期

本文探讨了在股票交易中包含冷冻期的最优买卖策略,通过动态规划算法解决最大利润问题,介绍了状态转移过程和代码实现,同时提供了空间优化方案。

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


时间:2020年7月10日
知识点:动态规划
题目链接: https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/

题目
给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

  • 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
  • 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。

示例
输入
[1,2,3,0,2]
输出:3
解释:对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]。

解法

  1. 我们用dp[i]表示第i天结束之后的累计的最大收益
  2. 第i天结束后有三种情况
    状态一:手上有股票,记为dp[i][0]
    状态二:手上没有股票,还处于冷冻期,记为dp[i][1]
    状态三:手上没有股票,不处于冷冻期,还没有买股票(称为观望期),记为dp[i][2]
  3. 状态转移
    1. 什么情况下能变成状态一?
      1. 原来就持有股票,即dp[i-1][0]
      2. 在第i天买入,什么情况下能买入?手上股票卖出了且过了冷冻期,即dp[i-1][2],买股票累计的最大收益就减少,减少的值是现在股票的价格
      3. dp[i][0] = max(dp[i-1][0],dp[i-1][2]-price[i])
    2. 什么情况下能变成状态二?
      1. 在昨天卖出了股票,昨天手上要有股票即dp[i-1][0],卖出股票收益增加,增加的值是现在股票的价格
      2. dp[i][1]=dp[i-1][0]+price[i]
    3. 什么情况下能变成状态三?
      1. 前天卖出股票,昨天手上没股票,且在冷冻期,今天解封可以买股票,即dp[i-1][1]
      2. 昨天手上没股票且没在冷冻期,处于等等期,即dp[i-1][2]
      3. dp[i][2]=max(dp[i-1][1],dp[i-1][2])
  4. 总共有n天的话,结果是max(dp[n-1][0],dp[n-1][1],dp[n-1][2]),但是在最后一天手上有股票也不能换钱,其实就是求max(dp[n-1][1],dp[n-1][2])
  5. 注意dp数组的边界
    dp[0][0] = -price[0] 若在第0天拥有股票,则就是在第0天买入,累积的收益为负数
    dp[0][1] = 0 第0天不存在冷冻期
    dp[0][2] = 0 在第0天没买股票,累积收益为0

代码

#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
 class Solution {
 public:
     int maxProfit(vector<int>& prices) {
         if (prices.empty())
            return 0;
         int num = prices.size();
         // dp[i][0]: 手上有股票时的累积最大收益
         // dp[i][1]: 手上没有股票,并且处于冷冻期中的累计最大收益
         // dp[i][2]: 手上没有股票,并且不在冷冻期中的累计最大收益
         vector<vector<int>> dp(num, vector<int>(3));
         dp[0][0] = -prices[0];
         for (int i = 1; i < num; 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][1], dp[i - 1][2]);
         }
         return max(dp[num - 1][1], dp[num - 1][2]);
     }
 };
 int main()
{
    vector<int> v(10);
    v[0]=1;v[1]=2;v[2]=3;v[3]=0;v[4]=2;
    Solution s;
    cout<<s.maxProfit(v);
    return 0;
}

优化空间,注意到上面的状态转移方程中,dp[i][X]只与 dp[i-1][X] 有关,而与dp[i-2][X]及之前的所有状态都无关,因此我们不必存储这些无关的状态

#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
    int maxProfit(vector<int>& prices) {
        if (prices.empty())
            return 0;
        int num = prices.size();
        // dp0: 手上有股票时的累积最大收益
        // dp1: 手上没有股票,并且处于冷冻期中的累计最大收益
        // dp2: 手上没有股票,并且不在冷冻期中的累计最大收益
        int dp0 = -prices[0];
        int dp1 = 0;
        int dp2 = 0;
        for (int i = 1; i < num; i++) {
            int tmp0 = max(dp0, dp2 - prices[i]);
            int tmp1 = dp0 + prices[i];
            int tmp2 = max(dp1, dp2);
            dp0 = tmp0;
            dp1 = tmp1;
            dp2 = tmp2;
            
        }
        return max(dp1, dp2);
    }
};
int main()
{
    vector<int> v(10);
    v[0]=1;v[1]=2;v[2]=3;v[3]=0;v[4]=2;
    Solution s;
    cout<<s.maxProfit(v);
    return 0;
}

今天也是爱zz的一天哦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值