力扣刷题-动态规划(股票收益-系列)

1 买卖股票最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0

一次买入卖出

1.1 递归关系

   设置二维数据dp,dp[i][0]代表第i天手上有股票的最大收益,可能是之前买的,也可能是今天买的,dp[i][1]代表第i天手上无股票的最大收益,可能本来就没有买,可能是卖了。

那么,当前日有股票的最大收益两种情况:

  1. 昨天也有股票的最大收益

  2. 今日第一次入股的成本,之前没有买过

而当前日无股票的最大收益:

  1. 昨天也无股票的最大收益
  2. 今日卖出的股价,加上昨天手上有股票的收益
  • 当日有股票的时候
    d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , − p r i c e [ i ] ) dp[i][0] = max(dp[i-1][0],-price[i]) dp[i][0]=max(dp[i1][0],price[i])

  • 当日无股票的时候
    d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , p r i c e [ i ] + d p [ i − 1 ] [ 0 ] ) dp[i][1] = max(dp[i-1][1],price[i]+dp[i-1][0]) dp[i][1]=max(dp[i1][1],price[i]+dp[i1][0])
    price[i]+dp[i-1][0]代表今日卖出,dp[i-1][0]是昨日持有股票的收益,加上今天卖出的价格price[i]才是最终今天卖出的收益

1.2 边界条件

  • 第一日有股票
    d p [ 0 ] [ 0 ] = − p r i c e [ 0 ] dp[0][0] = -price[0] dp[0][0]=price[0]

  • 第一日无股票
    d p [ 0 ] [ 1 ] = 0 dp[0][1] = 0 dp[0][1]=0

1.3 代码

class Solution {
    public int maxProfit(int[] prices) {
        if(prices==null||prices.length==0){
            return 0;
        }
        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 Math.max(dp[len-1][0],dp[len-1][1]);
    }
}

2 买卖股票最佳时机II

与第一题只改动了一行代码!

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润

区别:能买入卖出股票很多次!

2.1 递归关系

   设置二维数据dp,dp[i][0]代表第i天手上有股票的最大收益,可能是之前买的,也可能是今天买的,dp[i][1]代表第i天手上无股票的最大收益,可能本来就没有买,可能是卖了。

那么,当前日有股票的最大收益两种情况:

  1. 昨天也有股票的最大收益

  2. 今日入股的成本,加上昨天手上无股票的收益

而当前日无股票的最大收益:

  1. 昨天也无股票的最大收益
  2. 今日卖出的股价,加上昨天手上有股票的收益
  • 当日有股票的时候
    d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , − p r i c e [ i ] + d p [ i − 1 ] [ 1 ] ) dp[i][0] = max(dp[i-1][0],-price[i]+dp[i-1][1]) dp[i][0]=max(dp[i1][0],price[i]+dp[i1][1])

  • 当日无股票的时候
    d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , p r i c e [ i ] + d p [ i − 1 ] [ 0 ] ) dp[i][1] = max(dp[i-1][1],price[i]+dp[i-1][0]) dp[i][1]=max(dp[i1][1],price[i]+dp[i1][0])
    price[i]+dp[i-1][0]代表今日卖出,dp[i-1][0]是昨日持有股票的收益,加上今天卖出的价格price[i]才是最终今天卖出的收益

2.2 边界条件

  • 第一日有股票
    d p [ 0 ] [ 0 ] = − p r i c e [ 0 ] dp[0][0] = -price[0] dp[0][0]=price[0]

  • 第一日无股票
    d p [ 0 ] [ 1 ] = 0 dp[0][1] = 0 dp[0][1]=0

2.3 代码

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

3 买卖股票最佳时机III

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

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

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

最多买入卖出两次!设置dp[len][4]数组,表示第一次第二次持有与未持有的最大收益

3.1 递归关系

   设置二维数据dp,

dp[i][0]代表第i天第一次买卖手上有股票的最大收益,可能是之前买的,也可能是今天第一次买的,

dp[i][1]代表第i天第一次买卖手上无股票的最大收益,可能本来就没有买,可能是卖了;

dp[i][2]代表第i天第二次买卖手上有股票的最大收益,可能是之前第二次买的,也可能是今天第二次买,

dp[i][1]代表第i天第二次买卖手上无股票的最大收益,可能早就卖了第二次,可能是今天卖了;

那么,当前日第一次有股票的最大收益两种情况:

  1. 昨天也有股票的最大收益

  2. 今日第一次入股

而当前日第一次无股票的最大收益:

  1. 昨天也无股票的最大收益

  2. 今日卖出的股价,加上昨天手上有股票的收益

当前日第二次有股票的最大收益的两天情况:

  1. 昨天第二次有股票的收益(今天之前就已经买了第二次)
  2. 昨天第一次卖股票的收益-今天第二次入股的成本(今天买第二次)

而当前日第二次无股票的最大收益:

  1. 昨天第二次无股票的收益(今天之前就已经卖了第二次)
  2. 昨天第二次有股票的收益+今日股价(今日卖出第二次)
  • 当日第一次有股票的时候
    d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , − p r i c e [ i ] ) dp[i][0] = max(dp[i-1][0],-price[i]) dp[i][0]=max(dp[i1][0],price[i])

  • 当日第一次无股票的时候
    d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , p r i c e [ i ] + d p [ i − 1 ] [ 0 ] ) dp[i][1] = max(dp[i-1][1],price[i]+dp[i-1][0]) dp[i][1]=max(dp[i1][1],price[i]+dp[i1][0])

  • 当日第二次有股票的时候
    d p [ i ] [ 2 ] = m a x ( d p [ i − 1 ] [ 2 ] , d p [ i − 1 ] [ 1 ] − p r i c e [ i ] ) dp[i][2] = max(dp[i-1][2],dp[i-1][1]-price[i]) dp[i][2]=max(dp[i1][2],dp[i1][1]price[i])

  • 当日第二次无股票的时候
    d p [ i ] [ 3 ] = m a x ( d p [ i − 1 ] [ 3 ] , d p [ i − 1 ] [ 2 ] + p r i c e [ i ] ) dp[i][3] = max(dp[i-1][3],dp[i-1][2]+price[i]) dp[i][3]=max(dp[i1][3],dp[i1][2]+price[i])

3.2 边界条件

  • 第一日第一次有股票
    d p [ 0 ] [ 0 ] = − p r i c e [ 0 ] dp[0][0] = -price[0] dp[0][0]=price[0]

  • 第一日第一次无股票
    d p [ 0 ] [ 1 ] = 0 dp[0][1] = 0 dp[0][1]=0

  • 第一日第二次有股票
    d p [ 0 ] [ 0 ] = − p r i c e [ 0 ] dp[0][0] = -price[0] dp[0][0]=price[0]

  • 第一日第二次无股票
    d p [ 0 ] [ 0 ] = 0 dp[0][0] = 0 dp[0][0]=0

3.3 代码

class Solution {
    public int maxProfit(int[] prices) {
        if(prices==null||prices.length==0){
            return 0;
        }
        int len = prices.length;
        int[][]dp = new int[len][4];
        //初始化
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        dp[0][2] = -prices[0];
        dp[0][3] = 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]);
            //第二次有股票
            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]);
            
        }
        return Math.max(Math.max(dp[len-1][0],dp[len-1][1]),Math.max(dp[len-1][2],dp[len-1][3]));
    }
}

4 买卖股票最佳时机IV

给你一个整数数组 prices 和一个整数 k ,其中 prices[i] 是某支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 k 笔交易。也就是说,你最多可以买 k 次,卖 k 次。

最多可以买卖k次!

4.1 递归关系

   设置二维数据dp[len][2k],dp[i][0]代表第i天手上有股票的最大收益,可能是之前买的,也可能是今天买的,dp[i][1]代表第i天手上无股票的最大收益,可能本来就没有买,可能是卖了;dp[i][2]代表第二次买卖手上有股票的最大收益,dp[i][3]代表第二次买卖手上无股票的最大收益;

递推得知

dp[i][(k-1)*2]代表第k次买卖手上有股票的最大收益

dp[i][(k-1)*2+1]代表第k次买卖手上无股票的最大收益

  • 当日有股票的时候

    • 前一日有股票的最大收益
    • 前一日无股票的收益-当日入股市的成本**(第一次入股只需成本)**
      d p [ i ] [ ( k − 1 ) ∗ 2 ] = m a x ( d p [ i − 1 ] [ ( k − 1 ) ∗ 2 ] , − p r i c e [ i ] + i f ( k − 1 = = 0 ) ? 0 : d p [ i − 1 ] [ ( k − 1 ) ∗ 2 − 1 ] ) dp[i][(k-1)*2] = max(dp[i-1][(k-1)*2],-price[i]+if(k-1==0)?0:dp[i-1][(k-1)*2-1]) dp[i][(k1)2]=max(dp[i1][(k1)2],price[i]+if(k1==0)?0:dp[i1][(k1)21])
  • 当日无股票的时候

    • 前一个无股票的最大收益
    • 前一日有股票的最大收益+当日股市的股价

    d p [ i ] [ ( k − 1 ) ∗ 2 + 1 ] = m a x ( d p [ i − 1 ] [ ( k − 1 ) ∗ 2 + 1 ] , d p [ i − 1 ] [ ( k − 1 ) ∗ 2 ] + p r i c e [ i ] ) dp[i][(k-1)*2+1] = max(dp[i-1][(k-1)*2+1],dp[i-1][(k-1)*2]+price[i]) dp[i][(k1)2+1]=max(dp[i1][(k1)2+1],dp[i1][(k1)2]+price[i])
    price[i]+dp[i-1][0]代表今日卖出,dp[i-1][0]是昨日持有股票的收益,加上今天卖出的价格price[i]才是最终今天卖出的收益

2.2 边界条件

  • 第一日有股票(不管买入卖出折腾多少次)
    d p [ 0 ] [ ( k − 1 ) ∗ 2 ] = − p r i c e [ 0 ] dp[0][(k-1)*2] = -price[0] dp[0][(k1)2]=price[0]

  • 第一日无股票(不管买入卖出折腾多少次)
    d p [ 0 ] [ ( k − 1 ) ∗ 2 + 1 ] = 0 dp[0][(k-1)*2+1] = 0 dp[0][(k1)2+1]=0

2.3 代码

public class Solution {
    public int maxProfit(int k, int[] prices) {
        int n = prices.length;
        int[][] dp = new int[n][2 * k];
        //初始化
        for(int index=0;index<2*k;index++){
            if(index%2==0){
                dp[0][index] = -prices[0];
            }else{
                dp[0][index] = 0;
            }
        }
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < k; j++) {
                dp[i][j * 2] = Math.max(dp[i - 1][j * 2], -prices[i] + (j != 0 ? dp[i - 1][j * 2 - 1] : 0));
                dp[i][j * 2 + 1] = Math.max(dp[i - 1][j * 2 + 1], dp[i - 1][j * 2] + prices[i]);
            }
        }
        int ans = 0;
        for(int i=0;i<2*k;i++){
            ans = Math.max(ans,dp[n-1][i]);
        }
        return ans;
    }
}

5 买卖股票含冷冻期

5.1 递归关系

与第二题一样,无限制交易次数,但是交易一次后一天内不能再次交易

   设置二维数据dp,dp[i][0]代表第i天手上有股票的最大收益,可能是之前买的,也可能是今天买的,dp[i][1]代表第i天手上无股票的最大收益,可能本来就没有买,可能是卖了。

那么,当前日有股票的最大收益两种情况:

  1. 昨天也有股票的最大收益

  2. 今日入股的成本,加上前天手上无股票的收益

而当前日无股票的最大收益:

  1. 昨天也无股票的最大收益
  2. 今日卖出,加上昨天手上有股票的收益
  • 当日有股票的时候
    d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i − 2 ] [ 1 ] − p r i c e [ i ] ) dp[i][0] = max(dp[i-1][0],dp[i-2][1]-price[i]) dp[i][0]=max(dp[i1][0],dp[i2][1]price[i])

  • 当日无股票的时候
    d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] + p r i c e [ i ] ) dp[i][1] = max(dp[i-1][1],dp[i-1][0]+price[i]) dp[i][1]=max(dp[i1][1],dp[i1][0]+price[i])

2.2 边界条件

初始化两天

  • 第一日有股票
    d p [ 0 ] [ 0 ] = − p r i c e [ 0 ] dp[0][0] = -price[0] dp[0][0]=price[0]

  • 第一日无股票
    d p [ 0 ] [ 1 ] = 0 dp[0][1] = 0 dp[0][1]=0

  • 第二日有股票
    d p [ 1 ] [ 0 ] = m a x ( d p [ 0 ] [ 0 ] , d p [ 0 ] [ 1 ] − p r i c e [ 1 ] ) dp[1][0] = max(dp[0][0],dp[0][1]-price[1]) dp[1][0]=max(dp[0][0],dp[0][1]price[1])

  • 第二日无股票
    d p [ 1 ] [ 1 ] = m a x ( d p [ 0 ] [ 1 ] , d p [ 0 ] [ 0 ] + p r i c e [ 1 ] ) dp[1][1] = max(dp[0][1],dp[0][0]+price[1]) dp[1][1]=max(dp[0][1],dp[0][0]+price[1])

2.3 代码

class Solution {
    public int maxProfit(int[] prices) {
        if(prices==null||prices.length==0){
            return 0;
        }
        int len = prices.length;
        if(len<2){
            return 0;
        }
        int[][]dp = new int[len][2];
        //初始化
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        dp[1][0] = Math.max(dp[0][0],dp[0][1]-prices[1]);
        dp[1][1] = Math.max(dp[0][1],dp[0][0]+prices[1]);
        //开始遍历
        for(int i = 2;i<len;i++){
            dp[i][0] = Math.max(dp[i-1][0],dp[i-2][1]-prices[i]);
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
        }
        return Math.max(dp[len-1][0],dp[len-1][1]);
    }
}

6 买卖股票含手续费

5.1 递归关系

与第二题一样,无限制交易次数,交易一次后要扣钱fee

   设置二维数据dp,dp[i][0]代表第i天手上有股票的最大收益,可能是之前买的,也可能是今天买的,dp[i][1]代表第i天手上无股票的最大收益,可能本来就没有买,可能是卖了。

那么,当前日有股票的最大收益两种情况:

  1. 昨天也有股票的最大收益

  2. 今日入股的成本,加上昨天手上无股票的收益

而当前日无股票的最大收益:

  1. 昨天也无股票的最大收益
  2. 今日卖出,加上昨天手上有股票的收益,并且减去手续费fee
  • 当日有股票的时候

d p [ i ] [ 0 ] = m a x ( d p [ i − 1 ] [ 0 ] , d p [ i − 1 ] [ 1 ] − p r i c e [ i ] ) dp[i][0] = max(dp[i-1][0],dp[i-1][1]-price[i]) dp[i][0]=max(dp[i1][0],dp[i1][1]price[i])

  • 当日无股票的时候
    d p [ i ] [ 1 ] = m a x ( d p [ i − 1 ] [ 1 ] , d p [ i − 1 ] [ 0 ] + p r i c e [ i ] − f e e ) dp[i][1] = max(dp[i-1][1],dp[i-1][0]+price[i]-fee) dp[i][1]=max(dp[i1][1],dp[i1][0]+price[i]fee)

2.2 边界条件

初始化两天

  • 第一日有股票
    d p [ 0 ] [ 0 ] = − p r i c e [ 0 ] dp[0][0] = -price[0] dp[0][0]=price[0]

  • 第一日无股票
    d p [ 0 ] [ 1 ] = 0 dp[0][1] = 0 dp[0][1]=0

2.3 代码

class Solution {
    public int maxProfit(int[] prices, int fee) {
        if(prices==null||prices.length==0){
            return 0;
        }
        int len = prices.length;
        if(len<2){
            return 0;
        }
        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]-fee);
        }
        return Math.max(dp[len-1][0],dp[len-1][1]);
    }
}
  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值