LeetCode 309. Best Time to Buy and Sell Stock with Cooldown

250 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第36天,点击查看活动详情

LeetCode 309. Best Time to Buy and Sell Stock with Cooldown

给定一个整数数组prices,其中第 **prices[i] 表示第 i 天的股票价格 。​

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

  • 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。

注意: 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

 

示例 1:

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

示例 2:

输入: prices = [1]
输出: 0

 

提示:

  • 1 <= prices.length <= 5000
  • 0 <= prices[i] <= 1000

算法1

(动态规划) O(n)

设状态 f(i) 表示第 i 天结束后不持有股票的最大收益;g(i) 表示第 i 天结束后持有股票的最大收益。

初始时,f(0)=0,g(0)=−prices[0],其余待定。

转移时,f(i)=max(f(i−1),g(i−1)+prices[i]),表示第 i 天什么都不做,或者卖掉持有的股票。

g(i)=max(g(i−1),f(i−2)−prices[i]),表示第 i 天什么都不做,或者买当天的股票,但需要从上两天的结果转移。注意,如果 i<2 ,则 f(i−2) 当做 0。

最终答案为 f(n−1)。

时间复杂度

状态数为 O(n),每次转移时间为常数,时间复杂度为 O(n)。

空间复杂度

需要数组存储状态,故空间复杂度为 O(n)。

ac 代码

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if (n == 0)
            return 0;

        vector<int> f(n); // 当天不持有
        vector<int> g(n); // 当天持有

        f[0] = 0;
        g[0] = -prices[0];
        for (int i = 1; i < n; i++) {
            f[i] = max(f[i - 1], g[i - 1] + prices[i]);
            if (i >= 2)
                g[i] = max(g[i - 1], f[i - 2] - prices[i]);
            else
                g[i] = max(g[i - 1], -prices[i]);
        }
        return f[n - 1];
    }
};

算法2

(动态规划) O(n)

设状态 f(i) 表示第 i 天,当前结束不持有股票且当前没有发生卖出交易的最大收益;g(i) 表示第 ii 天结束后不持有股票,且当前刚刚卖出股票的最大收益;h(i) 表示当前持有股票的最大收益。\

转移时 f(i)=max(f(i−1),g(i−1)),表示构成第 i 天不持有股票且当天无交易有两种方式,一种是前一天也不持有且前一天没有卖出交易,另一种是前一天持有且前一天刚刚卖出股票;二者取最大值。
g(i)=h(i−1)+prices[i],表示构成第 i 天不持有股票且当天有交易仅有一种方式,即当天卖出前一天持有的股票。

h(i)=max(h(i−1),f(i−1)−prices[i]),表示构成第 i 天持有股票有两种方式,一种是前一天持有,另一种是前一天不持有且前一天无交易,但这一天刚刚买入。

最终答案为 max(f(n−1),g(n−1)),即最后一天不持有股票的两种情况。

时间复杂度

状态数为 O(n),每次转移时间为常数,时间复杂度为 O(n)。

空间复杂度

需要数组存储状态,故空间复杂度为 O(n)。 注意到状态转移之和前一层有关,故可以优化掉第一维。 每次提前取出前一层的值,用其更新为新的值即可。 所以空间复杂度可以优化到 O(1)。

ac 代码

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        const int INF = 1000000000;
        int n = prices.size();
        /*
        if (n == 0)
            return 0;
        vector<int> f(n); // 当天不持有,且当天没有卖出交易
        vector<int> g(n); // 当天不持有,且当天刚卖出
        vector<int> h(n); // 当天持有
        f[0] = 0;
        g[0] = -INF;
        h[0] = -prices[0];
        for (int i = 1; i < n; i++) {
            f[i] = max(f[i - 1], g[i - 1]);
            g[i] = h[i - 1] + prices[i];
            h[i] = max(h[i - 1], f[i - 1] - prices[i]);
        }
        return max(f[n - 1], g[n - 1]);
        */
        int f = 0;
        int g = -INF;
        int h = -INF;
        for (int i = 0; i < n; i++) {
            int new_f = max(f, g);
            int new_g = h + prices[i];
            int new_h = max(h, f - prices[i]);
            f = new_f;
            g = new_g;
            h = new_h;
        }
        return max(f, g);
    }
};