当前位置:   article > 正文

动态规划---买卖股票的最佳时机

买卖股票的最佳时机

说明

股票问题算是动态规划问题中的一个小分支,这里单独写一篇文章介绍。至于动态规划基础问题和详细的处理步骤我在我的另一篇文章中详细介绍过。具体解决步骤请移步观看——动态规划基础篇。如果想了解01背包问题和滚动数组相关内容请移步观看——动态规划——01背包问题

例题讲解

1.买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。
你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。
返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。
提示:

  • 1 <= prices.length <= 105
  • 0 <= prices[i] <= 104
1.1确定dp(dp table)数组及其下标的含义

这道题我们可以这样去理解,假设现在是第i天,那么此时有两种可能,一是我们此时手中持有股票,即dp[i][0]:表示第i天持有股票能获取的最大利润,二是我们手中不持有股票,即dp[i][1]:表示第i天不持有股票能获取的最大利润。

1.2确定递推公式

我们要得到dp[i][0]:表示第i天持有股票能获取的最大利润,显然有两种情况,一种是第i-1天就持有股票,注意理解题意,我们只能买入一次股票如果第i-1天持有,那么第i天的股票来自于第i-1天,即dp[i][0]=dp[i-1][0];另一种是第i-1天不持有,需要在今天买入,即dp[i][0]=-prices[i]。我们只需要选择这两种情况种较大的那一种即可,dp[i][0]=Math.max(dp[i-1][0],-prices[i])。
我们要得到dp[i][1]:表示第i天不持有股票能获取的最大利润。,同样也有两种情况,一种是第i-天就没有持有股票,那正好我们啥也不用做,即dp[i][1]=dp[i-1][1];另一种是第i-1天持有股票,需要我们在今天把他卖出,即dp[i][1]=dp[i-1][0]+prices[i]。我们只需要选择这两种情况种较大的那一种即可,dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[i])。
综上分析,递推公式如下:

dp[i][0]=Math.max(dp[i-1][0],-prices[i]);
dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[i])
  • 1
  • 2
1.3dp数组初始化

有递推公式可知,我们只需要初始化,dp[0][0]和dp[0][1]。
dp[0][0]:第0天持有股票获得的最大利润(数组下标从0开始,这样叙述更方便),显然持有股票意味着要花钱买入,所以dp[0][0]=-prices[0];
dp[0][1]:第0天不持有股票获得的最大利润(数组下标从0开始,这样叙述更方便),不持有股票有两种情况,一是没有买入股票,二是已经卖出股票(同一天买入和卖出,dp[0][0]=0),两种情况dp[0][1]都等于0,即dp[0][1]=0。

1.4代码示例
class Solution {
    public int maxProfit(int[] prices) {
        int len=prices.length;
        int[][] dp=new int[len][2];
        dp[0][0]=-prices[0];
        dp[0][1]=0;
        for(int i=1;i<len;i++){
            dp[i][0]=Math.max(dp[i-1][0],-prices[i]);
            dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
        }
        return dp[len-1][1];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
1.3空间优化
class Solution {
    public int maxProfit(int[] prices) {
       int len=prices.length;
       int buy=-prices[0],sell=0;
        for(int i=1;i<len;i++){
            buy=Math.max(buy,-prices[i]);
            sell=Math.max(sell,buy+prices[i]);
        }
        return sell;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

2.买卖股票的最佳时机||

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。
在每一天,你可以决定是否购买和/或出售股票。你在任何时候最多只能持有一股股票。你也可以先购买,然后在同一天出售。
返回你能获得的最大利润 。
提示:

  • 1 <= prices.length <= 3 * 104
  • 0 <= prices[i] <= 104
2.1确定dp(dp table)数组及其下标的含义

这道题我们可以这样去理解,假设现在是第i天,那么此时有两种可能,一是我们此时手中持有股票,即dp[i][0]:表示第i天持有股票能获取的最大利润,二是我们手中不持有股票,即dp[i][1]:表示第i天不持有股票能获取的最大利润。

2.2确定递推公式

我们要得到dp[i][0]:表示第i天持有股票能获取的最大利润,显然有两种情况,一种是第i-1天就持有股票,注意理解题意,我们只能买入一次股票如果第i-1天持有,那么第i天的股票来自于第i-1天(因为在任何时候最多只能持有一股股票,如果手中已经有了股票,在卖出之前,手上的股票不会再变),即dp[i][0]=dp[i-1][0];另一种是第i-1天不持有,需要在今天买入,但是此时我们需要特别注意一点,和第一个例题不同的是,我们现在可以多次进行购买/卖出,那么我们再够卖股票之前我们可能已经进行过交易,并且已经赚到钱,所以dp[i][0]=dp[i-1][1]-prices[i]。这和只能买卖一次又很大的区别,如果你只能买卖一次,那么如果你此时需要购买股票,说明你之前一定没有进行过交易,那么你一分钱都没有赚过,显然dp[i][0]=-prices[i]。

我们要得到dp[i][1]:表示第i天不持有股票能获取的最大利润。,同样也有两种情况,一种是第i-天就没有持有股票,那正好我们啥也不用做,即dp[i][1]=dp[i-1][1];另一种是第i-1天持有股票,需要我们在今天把他卖出,即dp[i][1]=dp[i-1][0]+prices[i]。我们只需要选择这两种情况种较大的那一种即可,dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]+prices[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][0]+prices[i])
  • 1
  • 2
2.3dp数组初始化

有递推公式可知,我们只需要初始化,dp[0][0]和dp[0][1]。
dp[0][0]:第0天持有股票获得的最大利润(数组下标从0开始,这样叙述更方便),显然持有股票意味着要花钱买入,所以dp[0][0]=-prices[0];
dp[0][1]:第0天不持有股票获得的最大利润(数组下标从0开始,这样叙述更方便),不持有股票有两种情况,一是没有买入股票,二是已经卖出股票(同一天买入和卖出,dp[0][0]=0),两种情况dp[0][1]都等于0,即dp[0][1]=0。

2.4代码示例
class Solution {
    public int maxProfit(int[] prices) {
        int len=prices.length;
        int[][] dp=new int[len][2];
        dp[0][0]=-prices[0];
        dp[0][1]=0;
        for(int i=1;i<len;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][0]+prices[i]);
        }
        return dp[len-1][1];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
2.5空间优化
class Solution {
    public int maxProfit(int[] prices) {
        int len=prices.length;
        int buy=-prices[0];
        int sell=0;
        for(int i=1;i<len;i++){
            buy=Math.max(buy,sell-prices[i]);
            sell=Math.max(sell,buy+prices[i]);
        }
        return sell;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

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

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

提示:

  • 1 <= prices.length <= 105
  • 0 <= prices[i] <= 105
3.1确定dp(dp table)数组及其下标的含义

由于我们最多可以完成两笔交易,因此在任意一天结束之后,我们会处于以下五个状态中的一种:
0:未进行过任何操作;
1:第一次买入;
2:第一次卖出;
3:第二次买入;
4:第二次卖出。

注意:“最多可以完成两笔交易”这句话的意思是我们再整个交易过程种一共可以进行两次“买入/卖出”,这个和第二道例题不同的是他限制了买入/卖出的次数。
所以:dp[i][j]中 i表示第i天,j为 [0 - 4] 五个状态,dp[i][j]表示第i天状态j所剩最⼤现⾦

3.2确定递推公式

需要特别注意的是dp[i][2]和dp[i][3]表示的是买入股票的状态,并不一定要在第i天买入股票,因为再第i天之前可能已经买入股票了。

由于第一个状态的利润显然为0 ,因此我们可以不用将其记录。

要达到dp[i][1]的状态有两种操作:
第一种:第i天买入股票,即dp[i][1]=-prices[i];(不管是哪一天第一次买入,因为好没有卖出过,不可能有收益,所以dp[i][1]显然等于当天股票价格的负数);
第二种:第i天没有操作,而是之前就已经买入过一次股票,即dp[i][1]=dp[i-1][1];
那么dp[i][1]究竟选 dp[i-1][0] - prices[i],还是dp[i - 1][1]呢?
⼀定是选最⼤的,所以 dp[i][1] =Math.max(-prices[i], dp[i - 1][1]);

要达到dp[i][2]的状态有两种操作:
第一种:第i天卖出股票,即dp[i][2]=dp[i-1][1]+pricesi;
第二种:第i天没有操作,而是之前就已经卖出过一次股票,即dp[i][1]=dp[i-1][2];

同理,dp[i][2] =Math.max(dp[i-1][1] + prices[i], dp[i - 1][2]);

同理,dp[i][3]=Math.max(dp[i-1][2]-prices[i],dp[i-1][3]);
同理,dp[i][4]=Math.max(dp[i-1][3]+prices[i],dp[i-1][4]);

dp[i][1] =Math.max(-prices[i], dp[i - 1][1]);
dp[i][2] =Math.max(dp[i-1][1]+prices[i], dp[i - 1][2]);
dp[i][3]=Math.max(dp[i-1][2]-prices[i],dp[i-1][3]);
dp[i][4]=Math.max(dp[i-1][3]+prices[i],dp[i-1][4]);
  • 1
  • 2
  • 3
  • 4
3.3dp数组初始化

有递推公式可知,我们只需要初始化,dp[0][1],dp[0][2],dp[0][3]和dp[0][4]。

dp[0][1]:第一次买入,显然等于-prices[0],即dp[0][1]=-prices[0];
dp[0][2]: 第一次卖出,在同一天买入卖出显然利润为0,即dp[0][2]=0;
dp[0][3]:第二从买入,因为不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票),所以第二次买入时,我们显然已经卖出了第一次买入的股票,赚了0元,所以dp[0][3]依旧等于-prices[0],即dp[0][3]=-prices[0];
dp[0][4]: 第二次卖出,在同一天买入卖出显然利润为0,即dp[0][4]=0;

3.4代码示例
class Solution {
    public int maxProfit(int[] prices) {
        int len=prices.length;
        int[][] dp=new int[len][5];
        dp[0][1]=-prices[0];
        dp[0][3]=-prices[0];

        for(int i=1;i<len;i++){
            dp[i][1]=Math.max(-prices[i],dp[i-1][1]);
            dp[i][2]=Math.max(dp[i-1][1]+prices[i],dp[i-1][2]);
            dp[i][3]=Math.max(dp[i-1][2]-prices[i],dp[i-1][3]);
            dp[i][4]=Math.max(dp[i-1][3]+prices[i],dp[i-1][4]);
        }
        return dp[len-1][4];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
3.5空间优化
class Solution {
    public int maxProfit(int[] prices) {
        int len=prices.length;
        int buy1=-prices[0],buy2=-prices[0],sell1=0,sell2=0;

        for(int i=1;i<len;i++){
            buy1=Math.max(buy1,-prices[i]);
            sell1=Math.max(sell1,buy1+prices[i]);
            buy2=Math.max(buy2,sell1-prices[i]);
            sell2=Math.max(sell2,buy2+prices[i]);
        }
        return sell2;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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

给定一个整数数组 prices ,它的第 i 个元素 prices[i] 是一支给定的股票在第 i 天的价格。
设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

提示:

  • 0 <= k <= 100
  • 0 <= prices.length <= 1000
  • 0 <= prices[i] <= 1000
4.1确定dp(dp table)数组及其下标的含义

由于我们最多可以完成k笔交易,因此在任意一天结束之后,我们会处于以下2k个状态中的一种:
0:未进行过任何操作;
1:第一次买入;
2:第一次卖出;
3:第二次买入;
4:第二次卖出;
5:第三次买入;
6:第三次卖出;

注意:“最多可以完成k笔交易”这句话的意思是我们再整个交易过程种一共可以进行k次“买入/卖出”,这个和第二道例题不同的是他限制了买入/卖出的次数,本题和第三道例题唯一的不同就是由一共可以进行两笔交易变为一共可以进行k笔交易。
所以:dp[i][j]表示第i天状态j所剩最⼤现⾦

4.2确定递推公式

其实通过观察我们可以发现当j为奇数时,我们是进行买入操作,当j为偶数时,我们是进行卖出操作。
想要达到dp[i][1]状态,有两种操作:
第一种:第i天之前就已经进行了第一次买入,沿用之前的第一次买入状态,即dp[i][1]=dp[i-1][1];
第二种:第i天进行第一次买入,dp[i][1]=dp[i-1][0]-pricesi;

这两种情况选最大的一种即可,dp[i][1]=Math.max(dp[i-1][1],dp[i-1][0]-prices[i]);

想要达到dp[i][2]状态,有两种操作:
第一种:第i天之前就已经进行了第一次卖出,沿用之前的第一次卖出状态,即dp[i][j]=dp[i-1][2];
第二种:第i天进行第一次卖出,dp[i][2]=dp[i-1][1]+prices[i];

这两种情况选最大的一种即可,dp[i][2]=Math.max(dp[i-1][2]],dp[i-1][1]+prices[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]+prices[i]);
    }
  • 1
  • 2
  • 3
  • 4
4.3dp数组初始化

第0天没有操作,这个最容易想到,就是0,即:dp[0][0] = 0;
第0天做第⼀次买⼊的操作,dp[0][1] = -prices[0];
第0天做第⼀次卖出的操作,这个初始值应该是多少呢?
⾸先卖出的操作⼀定是收获利润,整个股票买卖最差情况也就是没有盈利即全程⽆操作现⾦为0,
从递推公式中可以看出每次是取最⼤值,那么既然是收获利润如果⽐0还⼩了就没有必要收获这个利润
了。
所以dp[0][2] = 0;
第0天第⼆次买⼊操作,初始值应该是多少呢?
不⽤管第⼏次,现在⼿头上没有现⾦,只要买⼊,现⾦就做相应的减少。
第⼆次买⼊操作,初始化为:dp[0][3] = -prices[0];

总上分析,初始化代码为:

for(int j=1;j<2*k;j+=2){
   dp[0][j]=-prices[0];
}
  • 1
  • 2
  • 3
4.4代码示例

其实将k替换为2,这道题就是第三道例题的解答,即一空可以进行两次交易。

class Solution {
    public int maxProfit(int k, int[] prices) {
        int len=prices.length;
        if(len==0) return 0; //注意:此处数组长度可能为0
        int[][] dp=new int[len][2*k+1];
        for(int j=1;j<2*k;j+=2){
            dp[0][j]=-prices[0];
        }
        for(int i=1;i<len;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[len-1][2*k];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

5.最佳买卖股票时机含冷冻期

给定一个整数数组prices,其中第 prices[i] 表示第 i 天的股票价格 。​
设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):
卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。
注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

提示:

  • 1 <= prices.length <= 5000
  • 0 <= prices[i] <= 1000
5.1确定dp(dp table)数组及其下标的含义

由于存在冷冻期,所以任意一天结束后会有以下三种状态:
dp[i][0]:买入状态,可能是第i天买入,也可能时第i天之前就已经买入
dp[i][1]:卖出状态,但是在第i天卖出了股票,第i+1天处于冷冻期
dp[i][2]:卖出状态,第i天可以处于冷冻期也可以不处于冷冻期,只要保证第i+1天正常交易即可

注意:题目说“卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)”,虽然冷冻期是1天,但是从卖出股票的那一天算起,其实是两天,所以dp[i][1]:卖出状态,但是处于冷冻期,其实是指第i天卖出了股票,所以第i+1天处于冷冻期;
二dp[i][2]:卖出状态,并且不在冷冻期,是指不是在第i天卖出的,第i+1天可以正常买入股票。

所以dp[i][j]:第i天,处在j状态,所剩余的钱最多为dp[i][j]。

5.2确定递推公式

需要特别注意的是dp[i][0]表示的是买入股票的状态,并不一定要在第i天买入股票,因为再第i天之前可能已经买入股票了。

要达到dp[i][0]的状态有两种操作:
第一种:第i天买入股票并且第i天没有处于冷冻期,即dp[i][0]=dp[i-1][2]-prices[i];
第二种:第i天没有操作,而是之前就已经买入过股票,沿用之前的状态,即dp[i][0]=dp[i-1][0];
那么dp[i][0]究竟选dp[i-1][2]-prices[i],还是dp[i - 1][0]呢?
⼀定是选最⼤的,所以 dp[i][0] =Math.max(dp[i-1][2]-prices[i], dp[i - 1][0]);

要达到dp[i][1]的状态只有一种操作:
第i天卖出了持有的股票,使得第i+1天处于冷冻期,即dp[i-1][0]+prices[i];

要达到dp[i][2]的状态有两种操作:
第一种:第i-1天卖出的股票,第i天处于冷冻期,但是第i+1太难可以正常买入股票,即dp[i][2]=dp[i-1][1];
第二种:第i-1没有卖出股票,第i天也没有处于冷冻期,那么直接沿用之前的卖出状态,即dp[i][2]=dp[i-1][2];

同理,dp[i][2]=Math.max(dp[i-1][1],dp[i-1][2]);

综上分析,可得递推公式如下:

for(int i=1;i<prices.length;i++){
	dp[i][0] =Math.max(dp[i-1][2]-prices[i], dp[i - 1][0]);
	dp[i-1][0]+prices[i];
	dp[i][2]=Math.max(dp[i-1][1],dp[i-1][2]);
}
  • 1
  • 2
  • 3
  • 4
  • 5
5.3dp数组初始化

有递推公式可知,我们只需要初始化,dp[0][0],dp[0][1],dp[0][2]。

dp[0][0]:买入状态,可能是第i天买入,也可能时第i天之前就已经买入,此处使开始,显然dp[0][0]=-prices[0];
dp[0][1]和dp[0][2]显然都等于0

5.4代码示例
class Solution {
    public int maxProfit(int[] prices) {
        int len=prices.length;
        int[][] dp=new int[len][3];
        dp[0][0]=-prices[0];
        for(int i=1;i<len;i++){
           dp[i][0]=Math.max(dp[i-1][0],dp[i-1][2]-prices[i]);
           dp[i][1]=dp[i-1][0]+prices[i];
           dp[i][2]=Math.max(dp[i-1][1],dp[i-1][2]);
        }
        return Math.max(dp[len-1][1],dp[len-1][2]);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
5.5空间优化
class Solution {
    public int maxProfit(int[] prices) {
        int a=-prices[0],b=0,c=0;
        for(int i=1;i<prices.length;i++){
           int newA=Math.max(a,c-prices[i]);
           int newB=a+prices[i];
           int newC=Math.max(b,c);
		  //保存i-1的数据
           a=newA;
           b=newB;
           c=newC;
        }
        return Math.max(b,c);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

6.买卖股票的最佳时机含手续费

给定一个整数数组 prices,其中 prices[i]表示第 i 天的股票价格 ;整数 fee 代表了交易股票的手续费用。
你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。
返回获得利润的最大值。
注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。
提示:

  • 1 <= prices.length <= 5 * 104
  • 1 <= prices[i] < 5 * 104
  • 0 <= fee < 5 * 104
6.1确定dp(dp table)数组及其下标的含义

dp[i][0]:第i天持有股票获得利润的最大值;
dp[i][1]:第i天不持有股票获得利润的最大值;

6.2确定递推公式

需要特别注意的是dp[i][0]表示的是买入股票的状态,并不一定要在第i天买入股票,因为再第i天之前可能已经买入股票了。

要达到dp[i][0]的状态有两种操作:
第一种:第i天买入股票,那么首先第i-1天需要处于不持有股票状态,这是因为题目要求“如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了”,而且因为可以无限次交易,那么第i天之前可能已经进行过交易并赚到了钱,所以dp[i][0]=dp[i-1][1]-prices[i],即用之前赚到的钱减去第i天股票的价格;
第二种:第i天没有操作,而是之前就已经买入过股票,沿用之前的状态,即dp[i][0]=dp[i-1][0];

那么dp[i][0]究竟选dp[i-1][1]-prices[i],还是dp[i - 1][0]呢?
⼀定是选最⼤的,所以 dp[i][0] =Math.max(dp[i-1][1]-prices[i], dp[i - 1][0]);

要达到dp[i][1]的状态有两种操作:
第一种:第i天卖出的股票,那么第i-1天需要保持持有股票状态,并且用第i-1天持有股票状态获得利润的最大值加上第i天股票的价格,这里需要注意的是,如题“你每笔交易都需要付手续费”,所以在卖出时我们还需要减去手续费,即dp[i][1]=dp[i-1][0]+prices[i]-fee;
第二种:第i-1保持不持有股票状态,那么直接沿用之前的卖出状态,即dp[i][1]=dp[i-1][1];

同理,dp[i][1]=Math.max(dp[i-1][0]+prices[i]-fee,dp[i-1][1]);

综上分析,可得递推公式如下:

for(int i=1;i<prices.length;i++){
	dp[i][0] =Math.max(dp[i-1][1]-prices[i], dp[i - 1][0]);
	dp[i][1]=Math.max(dp[i-1][0]+prices[i]-fee,dp[i-1][1]);
}
  • 1
  • 2
  • 3
  • 4
6.3dp数组初始化

有递推公式可知,我们只需要初始化,dp[0][0],dp[0][1]
dp[0][0]=-prices[0];
dp[0][1]=0;
这里注意一下dp[0][1],其实dp[0][1]此时由两种选择,一种时买入再卖出但是需要缴纳手续费fee,另一种是直接不买入,显然选择第第二种即dp[0][1]=0;

6.4代码示例
class Solution {
    public int maxProfit(int[] prices, int fee) {
        int len=prices.length;
        int[][] dp=new int[len][2];
        dp[0][0]=-prices[0];
        for(int i=1;i<len;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][0]+prices[i]-fee);
        }

        return dp[len-1][1];
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
6.5空间优化
class Solution {
    public int maxProfit(int[] prices, int fee) {
        int len=prices.length;
        int a=-prices[0],b=0,newA=0,newB=0;
        for(int i=1;i<len;i++){
            newA=Math.max(a,b-prices[i]);
            newB=Math.max(b,a+prices[i]-fee);
            a=newA;
            b=newB;
        }

        return b;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/693570
推荐阅读
相关标签
  

闽ICP备14008679号