leetcode刷题(53)——309. 最佳买卖股票时机含冷冻期

一、题目

给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。​

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

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

示例:

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

二、思路——动态规划

(1)问题拆解:

题目中冷冻期的意思是,卖出股票后,你无法在第二天买入股票 。也就是说,要想知道今天的持股状态,就要知道前一天的状态是什么。

对于第 i 天,有持股和不持股两种状态。其中,持股有两种可能,一种是昨天就是持股,今天继承昨天的,另一种是今天买入了股票;而不持股则有两种可能,一种是今天卖出了股票所以不持有,另一种是昨天卖出了股票所以今天不持有。总的来说,今天的状态可以分为三种情况,我们分别用 0、1、2 来表示:

  • 0——持股;
  • 1——前一天就没有股票,今天也没买,所以今天不持股;
  • 2——今天卖出股票,所以不持股。
(2)定义状态:

问题拆解中我们分析出了每一天的持股状态,也就可以表示出第 i 天的收益,所以我们定义状态为:第 i 天的收益。我们定义二维状态数组 dp[i][j] 存储每天的收益,其中 i 表示天数,j = 0,1,2 表示这一天的持股状态。

(3)推导状态转移方程:

每一天的持股状态有三种情况,下面我们就分析每种情况下,当天的收益是多少。

  • 第 i 天持股:dp[i][0]。一种是昨天就持股,今天继承昨天的,则有 dp[i][0] = dp[i - 1][0];一种是今天买入了股票,前提是昨天没有卖,也就是昨天处于 “不持股且没有卖出” 这个状态下,今天才能买,则有 dp[i][0] = dp[i - 1][1] - prices[i]。所以
    d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] − p r i c e s [ i ] ) dp[i][0] = max(dp[i - 1][0], dp[i - 1][1] - prices[i]) dp[i][0]=max(dp[i1][0],dp[i1][1]prices[i])
  • 第 i 天不持股,因为第 i - 1 天就没有股票,今天也没买:dp[i][1]。第 i - 1 天没有股票就是问题拆解中的两种情况,则第 i 天的收益为
    d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 2 ] ) dp[i][1] = max(dp[i - 1][1], dp[i - 1][2]) dp[i][1]=max(dp[i1][1],dp[i1][2])
  • 第 i 天不持股,因为今天卖出了股票:dp[i][2]。今天卖出了股票,说明昨天一定是持股的,则
    d p [ i ] [ 2 ] = d p [ i − 1 ] [ 0 ] + p r i c e s [ i ] dp[i][2] = dp[i - 1][0] + prices[i] dp[i][2]=dp[i1][0]+prices[i]
(4)寻找边界条件:

以第一天作为初始状态,对dp数组初始化。

  • dp[0][0] = -1*prices[0];// 第一天只买入
  • dp[0][1] = 0;// 第一天本来就不持有
  • dp[0][2] = 0;//可以理解成第一天买入又卖出,那么第一天就是“不持股且当天卖出了”这个状态了,其收益为 0,所以初始化为 0。

三、代码

class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        if(n < 2)
            return 0;
        int[][] dp = new int[n][3];
        // 初始化
        dp[0][0] = -1 * prices[0];
        dp[0][1] = 0;
        dp[0][2] = 0;
        for(int i = 1; i < n; i++){
            dp[i][0] = Math.max(dp[i - 1][0], dp[i - 1][1] - prices[i]);
			dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][2]);
			dp[i][2] = dp[i - 1][0] + prices[i];
        }
        return Math.max(dp[n - 1][1], dp[n - 1][2]);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值