0713-2020-dp专题-股票等等

第一种,只卖买一次,那就是找出前面最小的买入价格,在最后卖出即可。

121.买卖股票的最佳时机

	public int maxProfit(int[] prices) {
        if(prices == null || prices.length == 0) return 0;
        int min = prices[0];
        int max = 0;
        for(int i = 1;i < prices.length;i++) {
            if(prices[i] - min > max) {
                max = prices[i] - min;
            }
            min = Math.min(min,prices[i]);
        }
        return max;
    }

122.买卖股票的最佳时机②,无限次买卖

贪心,就是当天可以买入股票同时卖出股票,所以每天都可以操作。

	public int maxProfit(int[] prices) {
        if(prices == null || prices.length == 0) return 0;
        int res = 0;
        for(int i = 1;i < prices.length;i++) {
            if(prices[i] > prices[i - 1]) {
                res += prices[i] - prices[i - 1];
            }
        }
        return res;
    }

dp也可以做,dp也不难,注意注释

	public int maxProfit(int[] prices) {
        if(prices == null || prices.length == 0) return 0;
        int len = prices.length;
        //dp[天数]][0,1代表,0当天不持有,1代表当天持有]]
        int[][] dp = new int[len][2];
        dp[0][0] = 0;
        dp[0][1] = -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]);
        }
        return dp[len - 1][0];
    }

123.买卖股票的最佳时机③,只能买卖两次

自己可以写出来的dp

	public int maxProfit(int[] prices) {
        if(prices == null || prices.length == 0) return 0;
        int len = prices.length;
        //dp[天数][0,当前不持有股票,1代表当前持有股票][0,没有交易过,1交易过1次,2交易过两次],卖出才算一次交易完成
        int[][][] dp = new int[len][2][3];
        //第一天不持有股票都算是0
        dp[0][1][0] = - prices[0];
        dp[0][1][1] = - prices[0];
        for(int i = 1;i < len;i++) {
            dp[i][0][0] = dp[i - 1][0][0];
            dp[i][1][0] = Math.max(dp[i - 1][1][0],dp[i - 1][0][0] - prices[i]);
            dp[i][0][1] = Math.max(dp[i - 1][0][1],dp[i - 1][1][0] + prices[i]);
            dp[i][1][1] = Math.max(dp[i - 1][1][1],dp[i - 1][0][1] - prices[i]);
            dp[i][0][2] = Math.max(dp[i - 1][0][2],dp[i - 1][1][1] + prices[i]);
        }
        return Math.max(dp[len - 1][0][0],Math.max(dp[len - 1][0][1],dp[len - 1][0][2]));
    }

二维数组

	public int maxProfit(int[] prices) {
        if(prices == null || prices.length == 0) return 0;
        int len = prices.length;
        //dp[天数][0,未交易,1买入一次,2完成交易一次,3买入两次,4完成交易两次]
        int[][] dp = new int[len][5];
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        dp[0][2] = 0;
        dp[0][3] = -prices[0];
        dp[0][4] = 0;
        for(int i = 1;i < len;i++) {
            dp[i][0] = 0;
            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 Math.max(dp[len - 1][0],Math.max(dp[len - 1][2],dp[len - 1][4]));
    }

一维数组

	public int maxProfit(int[] prices) {
        if(prices == null || prices.length == 0) return 0;
        int len = prices.length;
        //dp[0,未交易,1买入1次,2完成交易1次,3买入第二次,4完成交易两次]
        int[] dp = new int[5];
        dp[0] = 0;
        dp[1] = - prices[0];
        dp[2] = 0;
        dp[3] = - prices[0];
        dp[4] = 0;
        for(int i = 1;i < len;i++) {
            dp[1] = Math.max(dp[1],dp[0] - prices[i]);
            dp[2] = Math.max(dp[2],dp[1] + prices[i]);
            dp[3] = Math.max(dp[3],dp[2] - prices[i]);
            dp[4] = Math.max(dp[4],dp[3] + prices[i]);
        }
        return Math.max(dp[0],Math.max(dp[2],dp[4]));
    }

既然可以用一维数组,那就可以用常数级别的变量代替。
使用滚动数组,降低空间复杂度,是我没想到的。

	public int maxProfit(int[] prices) {
        if(prices == null || prices.length == 0) return 0;
        int len = prices.length;
        //[notYet,未交易,firstBuy买入1次,firstGet完成交易1次,secondBuy买入第二次,secondGet完成交易两次]
        int notYet = 0;
        int firstBuy = - prices[0];
        int firstGet = 0;
        int secondBuy = - prices[0];
        int secondGet = 0;
        for(int i = 1;i < len;i++) {
            firstBuy = Math.max(firstBuy,notYet - prices[i]);
            firstGet = Math.max(firstGet,firstBuy + prices[i]);
            secondBuy = Math.max(secondBuy,firstGet - prices[i]);
            secondGet = Math.max(secondGet,secondBuy + prices[i]);
        }
        return Math.max(notYet,Math.max(firstGet,secondGet));
    }

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

思路和完成两次是一致的,但是需要注意的是k数值很大的情况,k很大就会直接超出内存限制,因为要创建数组就直接创建一个k长的三维数组,直接超内存了。所以只要k > len / 2就直接用不限次数的贪心来做就能解决这个问题。

	public int maxProfit(int k, int[] prices) {
        if(prices == null || prices.length == 0) return 0;
        int len = prices.length;
        if(k * 2 >= len) {
            return greedy(prices);
        }
        //dp[天数][0,不持有,1,持有][交易次数,卖出才算交易完成]
        int[][][] dp = new int[len][2][k + 1];
        for(int i = 0;i <= k;i++) {
            dp[0][1][i] = - prices[0];
        }
        for(int i = 1;i < len;i++) {
            dp[i][0][0] = 0;
            dp[i][1][0] = Math.max(dp[i - 1][1][0],dp[i - 1][0][0] - prices[i]);
            for(int j = 1;j <= k;j++) {
                dp[i][0][j] = Math.max(dp[i - 1][0][j],dp[i - 1][1][j - 1] + prices[i]);
                dp[i][1][j] = Math.max(dp[i - 1][1][j],dp[i - 1][0][j] - prices[i]);
            } 
        }
        int max = 0;
        for(int i = 0;i <= k;i++) {
            max = Math.max(max,dp[len - 1][0][i]);
        }
        return max;
        
    }
    public int greedy(int[] prices) {
        int res = 0;
        for(int i = 1;i < prices.length;i++) {
            if(prices[i] > prices[i - 1]) {
                res += (prices[i] - prices[i - 1]);
            }
        }
        return res;
    }

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

状态转移方程不唯一,这个解法只是一种,注意看dp的定义。
代码来源:
李威威
代码链接:
https://leetcode-cn.com/problems/best-time-to-buy-and-sell-stock-with-cooldown/solution/dong-tai-gui-hua-by-liweiwei1419-5/

	public int maxProfit(int[] prices) {
        if(prices == null || prices.length == 0) return 0;
        int len = prices.length;
        //dp[天数][0,不持有,1,持有非冷冻期,2,不持有,冷冻期]
        int[][] dp = new int[len][3];
        dp[0][0] = 0;
        dp[0][1] = -prices[0];
        dp[0][0] = 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][2] - prices[i]);
            dp[i][2] = dp[i - 1][0];
        }
        return Math.max(dp[len - 1][0],dp[len - 1][2]);
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值