round1/day23补/动规/股票问题2

1. 关于动规-股票

分成两种状态持有[0]不持有[1],再拆分两种子情况:

注意理解什么叫“持有”而不是“卖出”

  1. 在第i天持有 dp[i][0]
    • 在第i天买入 =dp[i-1][1]-prices[i]
      • 什么是-prices[i]?——目的是找到最小的-price[i],让买入值最低。因为一开始和他比较的值就是price[0]的买入价,而不是0
    • 在以前买入 =dp[i-1][0]
  2. 在第i天不持有 dp[i][1]
    • 在第i天卖出 =dp[i-1][0]+prices[i]
    • 在以前卖出 =dp[i-1][1]

2. 例题

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

思路

同上,主要考虑的是0/1状态的改变
情形:股票-考虑持有状态-限制交易次数(状态+1)

  • 创建dp:在第i天时,持有股票的最大金额
  • 初始化:对买入状态都进行填充
    • 注意,不用写第一天不购买的情况!接下来的递推中,可以假设第一天购买了,然后通过比价的方式去把太贵的买入价-prices[0]洗掉
  • 递推:当天持有[1.当天买入 2.以前买入] + 当天不持有[1.当天卖出 2.以前卖出]
    • 双层递归,统计当遍历到第i天时,其持有情况从1~限制次数(2)的所有情况
  • 遍历顺序:递增,每天需要以前一天的情况为基础

代码实现

class Solution {
    public int maxProfit(int[] prices) {
        int len = prices.length;
        int[][][] dp=new int[len][3][2];

        //特殊情况:空值或者只有一天
        if(prices==null || prices.length==1){
            return 0;
        }
        //初始化:注意!这里不用写第一天不购买的情况!接下来的递推中,可以假设第一天购买了,然后通过比价的方式去把太贵的买入价-prices[0]洗掉
        for(int j=1;j<=2;j++){
            dp[0][j][0]=-prices[0]; 
        }

        //递推:
        for(int i=1;i<prices.length;i++){
            for(int j=1;j<=2;j++){
                //当天持有:1.当天买入 2.以前买入
                dp[i][j][0]=Math.max(dp[i-1][j-1][1]-prices[i],dp[i-1][j][0]);
                //当天不持有:1.当天卖出 2.以前卖出
                dp[i][j][1]=Math.max(dp[i-1][j][0]+prices[i],dp[i-1][j][1]);
            }
        }
        return Math.max(dp[len-1][2][0],dp[len-1][2][1]);
    }
}

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

思路

同上,情形:股票-考虑持有状态-限制交易次数(状态+1)

代码实现

class Solution {
    public int maxProfit(int k, int[] prices) {
        int len = prices.length;
        int[][][] dp=new int[len][k+1][2];

        //特殊情况:空值或者只有一天
        if(prices==null || prices.length==1){
            return 0;
        }
        //初始化:注意!这里不用写第一天不购买的情况!接下来的递推中,可以假设第一天购买了,然后通过比价的方式去把太贵的买入价-prices[0]洗掉
        for(int j=1;j<=k;j++){
            dp[0][j][0]=-prices[0]; //问:第一天购买j不是撑死了是1吗?为什么需要把所有的j都填上?
        }


        //递推:
        for(int i=1;i<prices.length;i++){
            for(int j=1;j<=k;j++){
                //当天持有:1.当天买入 2.以前买入
                dp[i][j][0]=Math.max(dp[i-1][j-1][1]-prices[i],dp[i-1][j][0]);
                //当天不持有:1.当天卖出 2.以前卖出
                dp[i][j][1]=Math.max(dp[i-1][j][0]+prices[i],dp[i-1][j][1]);
            }
        }
        return Math.max(dp[len-1][k][0],dp[len-1][k][1]);
    }
}

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

思路

同上,情形:股票-考虑持有状态-有冷冻期(冷冻1天)
其他同上,
初始化考虑要写前两天的情况,而非没有冷冻期时的第一天

递推考虑

  • i天持有:
    • 今天买 dp[i-2][1]-prices[i]
    • 以前买 dp[i-1][0]
  • i天不持有:
    • 今天卖 dp[i-1][0]+prices[i]
    • 以前卖 dp[i-1][1]

代码实现

lass Solution {
    public int maxProfit(int[] prices) {
        //创建dp
        int[][] dp=new int[prices.length][2];
		
		//特殊情况
        if(prices==null || prices.length==1) return 0;

		//初始化
        dp[0][0]=-prices[0];
        dp[0][1]=0;
        
        dp[1][0]=Math.max(dp[0][0],-prices[1]);
        dp[1][1]=Math.max(dp[0][0] + prices[1], dp[0][1]);
		
		//递推
        for(int i=2;i<prices.length;i++){
            dp[i][0]=Math.max(dp[i-2][1]-prices[i],dp[i-1][0]);
            dp[i][1]=Math.max(dp[i-1][0]+prices[i],dp[i-1][1]);
        }

        return Math.max(dp[prices.length-1][0],dp[prices.length-1][1]);
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值