LeetCode Top 100 Liked Questions 309. Best Time to Buy and Sell Stock with Cooldown (Java版; Medium)

welcome to my blog

LeetCode Top 100 Liked Questions 309. Best Time to Buy and Sell Stock with Cooldown (Java版; Medium)

题目描述
Say you have an array for which the ith element is the price of a given stock on day i.

Design an algorithm to find the maximum profit. You may complete as many transactions as you like (ie, buy one and sell one share of the stock multiple times) with the following restrictions:

You may not engage in multiple transactions at the same time (ie, you must sell the stock before you buy again).
After you sell your stock, you cannot buy stock on next day. (ie, cooldown 1 day)
Example:

Input: [1,2,3,0,2]
Output: 3 
Explanation: transactions = [buy, sell, cooldown, buy, sell]
class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        if(n==0){
            return 0;
        }
        int[][] dp = new int[n][3];
        dp[0][1] = -prices[0];
        for(int i=1; i<n; i++){
            dp[i][0] = Math.max(dp[i-1][0], dp[i-1][2]);
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]-prices[i]);
            dp[i][2] = Math.max(dp[i-1][2], dp[i-1][1]+prices[i]);
        }
        return Math.max(dp[n-1][0], dp[n-1][2]);
    }
}
第二次做; 核心: 1)三个状态: 持有股票; 不持有股票(没有买入); 不持有股票(冷冻)

class Solution {
    public int maxProfit(int[] prices) {
        //冷冻期的存在会导致递归关系改变; 状态的数量没变: 天数和是否持有股票 ?
        //持有股票; 不持有股票(没有买入); 不持有股票(冷冻)
        if(prices==null || prices.length==0){
            return 0;
        }
        int n = prices.length;
        int[][] dp = new int[n][3];
        dp[0][1] = -prices[0];
        for(int i=1; i<n; i++){
            dp[i][0] = Math.max(dp[i-1][0], dp[i-1][2]);
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0] - prices[i]);
            dp[i][2] = dp[i-1][1] + prices[i];
        }

        return Math.max(dp[n-1][0], dp[n-1][2]);
    }
}
力扣题解还是用了两个状态, 如何区分是否位于冻结期?
作者的转移方程为:
dp[i][0] = max(dp[i-1][0], dp[i-1][1] + prices[i])
dp[i][1] = max(dp[i-1][1], dp[i-2][0] - prices[i])
解释:第 i 天选择 buy 的时候,要从 i-2 的状态转移,而不是 i-1 。


问题: 如何判断i-1天是否处于冷冻期?
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])

添加“冷冻期”条件后,dp[i-1][0] - prices[i]代表的“i-1天买入”不一定能成立,要再判断“i-2天是否存在卖出行为”

所以进一步拆解

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

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

其中dp[i-2][1] + prices[i-1]代表着“i-1发生了卖出行为”,有违题意,应予删除,得下式,与答主解答相一致:

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

int maxProfit_with_cool(int[] prices) {
    int n = prices.length;
    int dp_i_0 = 0, dp_i_1 = Integer.MIN_VALUE;
    int dp_pre_0 = 0; // 代表 dp[i-2][0]
    for (int i = 0; i < n; i++) {
        int temp = dp_i_0;
        dp_i_0 = Math.max(dp_i_0, dp_i_1 + prices[i]);
        dp_i_1 = Math.max(dp_i_1, dp_pre_0 - prices[i]);
        dp_pre_0 = temp;
    }
    return dp_i_0;
}
第一次做; 要会画状态转移图, 理解每个状态的含义, 非常方便理解; 如何知道有几个状态? 从本题的经验来看就是, 有几中操作就有几个状态, 可以这么说, 执行完一个操作就对应一个状态; 状态的个数可能可以压缩, 但是先别考虑那么多
class Solution {
    public int maxProfit(int[] prices) {
        if(prices==null || prices.length==0)
            return 0;
        int n = prices.length;
        //持有股票
        int[] s0 = new int[n];
        //不持有股票, 因为今天卖出
        int[] s1 = new int[n];
        //不持有股票, 因为今天rest
        int[] s2 = new int[n];
        //initialize
        s0[0] = -prices[0];
        s1[0] = Integer.MIN_VALUE;
        s2[0] = 0;
        for(int i=1; i<n; i++){
            s0[i] = Math.max(s0[i-1], s2[i-1] - prices[i]);
            s2[i] = Math.max(s1[i-1], s2[i-1]);
            s1[i] = s0[i-1] + prices[i];
        }
        return Math.max(s1[n-1], s2[n-1]);
    }
}
两种状态转移图; 第一种是最自然的想法; 第二种是第一种状态压缩后的结果; 务必掌握第一种

股票问题通解; LC121

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值