代码随想录算法训练营第五十天 | 123.买卖股票的最佳时机III 188.买卖股票的最佳时机IV

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

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

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

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

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

按照题目描述每天的操作状态可以分为五个状态

0:没有操作

1:第一天持有股票

2:第一天不持有股票

3:第二天持有股票

4:第二天不持有股票

动规五部曲:

  1. 确定dp数组及其下标含义

dp[i][j]表示第i天的0-4个中的j状态下最大金额

  1. 确定递推公式

dp[i][1]的状态下有两种可能:

第i天买入股票:dp[i][1]=dp[i-1][0]-prices[i]

第i-1天买入股票,第i天保持:dp[i][1]=dp[i-1][1]

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

dp[i][2]的状态下有两种可能:

第i天不持有股票:dp[i][2]=dp[i-1][1]+prices[i];

第i-1天不持有,第i天保持:dp[i][2]=dp[i-1][2];

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

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

dp[i][4]=max(dp[i-1][4],dp[i-1][3]+prices[0]);

  1. dp数组初始化

dp[0][1]=-prices[0]

dp[0][3]=-prices[0]

其他下标被设置为0即可

  1. 确定遍历顺序

因为后一个状态需要由前一个状态推导得出,所以需要从前向后遍历

  1. 举例推导dp数组

    prices=[1 2 3 4 5]

    dp[i][0]=[0 0 0 0 0]

    dp[i][1]=[-1 -1 -1 -1 -1]

    dp[i][2]=[0 1 2 3 4]

    dp[i][3]=[-1 -1 -1 -1 -1]

    dp[i][4]=[0 1 2 3 4]

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

    }
}

188. 买卖股票的最佳时机 IV

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

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

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

输入:k = 2, prices = [2,4,1]
输出:2
解释:在第 1(股票价格 = 2) 的时候买入,在第 2(股票价格 = 4) 的时候卖出,这笔交易所能获得利润 = 4-2 = 2

这道题和上一题很类似不同之处就是上一道题明确告诉了2笔交易所以状态为5中,本题给出k比交易状态即为2*k+1,所以我们只需要在上一题的基础上再嵌套一层循环又来遍历j

动规五部曲

  1. 确定dp数组及其下标含义

dp[i][j]表示第i天j状态下,所剩下最大金额为dp[i][j]

  1. 确定递推公式

dp[i][1]表示第i天买入股票的状态

所以dp[i][1]状态可能存在两种操作:

①第i天买入股票:dp[i][1]=dp[i-1][0]-peices[i];

②第i-1天买入股票,第i天保持状态:dp[i][1]=dp[i-1][1]

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

dp[i-2]状态同样也存在以下两种操作:

①第i天卖出股票 dp[i][2]=dp[i-1][1]+prices[i]

②第i-1天卖出股票,第i天保持 dp[i][2]=dp[i-1][2]

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

  1. dp数组初始化

每次买入状态都将dp[i][j]=-prices[0]

  1. 确定遍历顺序

从前往后遍历

  1. 举例推导dp数组
class Solution {
    public int maxProfit(int k, int[] prices) {
        if(prices==null||prices.length==0){
            return 0;
        }
        int[][] dp=new int[prices.length][2*k+1];
        for(int j=1;j<2*k;j+=2){
            dp[0][j]=-prices[0];
        }
        for(int i=1;i<prices.length;i++){
            for(int j=0;j<2*k-1;j+=2){
                //第一天的操作
                dp[i][j+1]=Math.max(dp[i-1][j+1],dp[i-1][j]-prices[i]);
                //第二天的操作
                dp[i][j+2]=Math.max(dp[i-1][j+2],dp[i-1][j+1]+prices[i]);
            }

        }
        return dp[prices.length-1][2*k];

    }
}

你可能感兴趣的:(算法,动态规划,leetcode)