123.买卖股票的最佳时机 Ⅲ

123.买卖股票的最佳时机Ⅲ

题目

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

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

示例 1:

输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
     随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。

示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。   
     注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。   
     因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:

输入:prices = [7,6,4,3,1] 
输出:0 
解释:在这个情况下, 没有交易完成, 所以最大利润为 0。

示例 4:

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

提示:

1 <= prices.length <= 105
0 <= prices[i] <= 105

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

题解

这道题和之前的区别在于:限制了买卖的次数,最多只允许两次交易。
121题是交易1次,122题是交易n次。

题目只问最大利润,没有问这几天具体哪一天买、哪一天卖,因此可以考虑使用 动态规划 的方法来解决。

  • 动态规划用于求解 多阶段决策问题 ;
  • 动态规划问题的问法:只问最优解,不问具体的解;

之前有两个状态,持有和不持有,但是现在限制了买卖次数,状态需要细化,第一次持有(买入)状态,第二次持有(买入)状态,第一次不持有(卖出)状态,第一次不持有(卖出)状态
dp[i][j] i表示天数,j表示状态
0:没有状态无操作
1:第一次买入
2:第一次买出
3:第二次卖入
4:第二次卖出

思考一下状态如何转移的?

第i天是第一次买入状态

  • 假设第i天执行买入操作,dp[i][1] = dp[i-1][0] -pricesi
  • 假设第i天没有执行买入操作,dp[i][1] = dp[i-1][1]
    dp[i][1] = Math.max(dp[i-1][0] -prices[i],dp[i-1][1])

第i天是第一次卖出状态

  • 假设第i天执行买入操作,dp[i][2] = dp[i-1][1] + prices[i]
  • 假设第i天没有执行买入操作,dp[i][2] = dp[i-1][2]
    dp[i][2] = Math.max(dp[i-1][1] + prices[i], dp[i-1][2])

第i天是第二次买入状态

  • 假设第i天执行买入操作,dp[i][3] = dp[i-1][2] - prices[i]
  • 假设第i天没有执行买入操作,dp[i][3] = dp[i-1][3]
    dp[i][3] = Math.max( dp[i-1][2] - prices[i],dp[i-1][3])

第i天是第二次卖出状态

  • 假设第i天执行卖出操作,dp[i][4] = dp[i-1][3] + prices[i]
  • 假设第i天没有执行卖出操作,dp[i][4] = dp[i-1][4]
    dp[i][4] = Math.max( dp[i-1][3] + prices[i],dp[i-1][4])

综合之后
dp[i][j] = Math.max(dp[i-1][j-1] - prices[i],dp[i-1][j]) j=1,=3
dp[i][j] = Math.max(dp[i-1][j-1] + prices[i],dp[i-1][j]) j=2,=4
如何初始化
dp[0][0] = 0
dp[0][1]=- prices[0]
dp[0][2]= 0
dp[0][3]= - prices[0]
dp[0][4]= 0

这里开始初始化为dp[0][3]=0,在举例推举dp数组时

①dp[1][4] = 2,这里明显是错误的,因为第一天明显只会交易一次
②第二次持有状态时买入可能会成负数,如果初始化0,那么将不会执行该买入。
说明这样初始化时错误的,那么应该初始化什么呢?
假设天数不足2天的时候,dp[i][3]和dp[i][4]不就没有意义了吗?
对于不足两天的情况,把第二次交易看成第一次交易即可,dp[0][3] = - prices[0],返回的dp[i][4]其实也是第一次交易的利润。
对于满足两天的情况,肯定是二次交易获得的利润更高。

这里根据状态推导出来,其实真实情况这种初始化是不存在

遍历顺序
i从小到大遍历,i依赖于i-1
j从小到大遍历,j依赖于j-1

滚动数组
根据递推式dp[i][j] = Math.max(dp[i-1][j-1] +或者- prices[i],dp[i-1][j])发现dp[i][j] 只依赖于前一天的状态,那么可以使用一维数组来表示,或者直接用两个变量来表示。

class Solution {
    public int maxProfit(int[] prices) {
        int leng = prices.length;
        if(leng==1)return 0;
        int dp [] = new int [5];
        dp[1] = -prices[0];
        dp[3] = -prices[0];
	for(int i=1;i<leng;i++){
            dp[1] = Math.max(dp[0] - prices[i],dp[1]);
	    dp[2] = Math.max(dp[1] + prices[i],dp[2]);
            dp[3] = Math.max(dp[2] - prices[i],dp[3]);
            dp[4] = Math.max(dp[3] + prices[i],dp[4]);
	}
        return dp[4];
    }
}

通用性

https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-iii/solution/java-dong-tai-gui-hua-by-programmery-fldq/

这个解法更具有通用性与好理解。这里记录,方便学习时查看。

posted @ 2021-10-29 16:58  rananie  阅读(17)  评论(0编辑  收藏  举报