力扣爆刷第130天之动态规划五连刷(一网打尽买卖股票全家桶)

力扣爆刷第130天之动态规划五连刷(买卖股票问题全家桶)

总结:

对于买卖股票问题,是一个特殊的问题,每一天都有两种状态:
持有股票,和不持有股票
每一种状态又有两种选择:
今天才持有,和之前就已经持有。或者今天才不持有,和之前就已经不持有
搞清楚这个就简单了,因为动态规划无非就是状态与选择,剩下的变体就是买卖次数的不同。

一、121. 买卖股票的最佳时机

题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock/description/
思路:买卖股票的最佳时机,本题只能买卖一次,求余额最多。自然就是每一天有两种状态,持有或者不持有。
持有又有两种选择,今天才持有和之前就已经持有,递推公式为dp[i][0] = max(dp[i-1][0], -nums[i])。
不持有又有两种选择,今天才不持有和之前就已经不持有,递推公式为dp[i][1] = max(dp[i-1][1], dp[i][0]+nums[i])。

另外:本题贪心也可以做,直接遍历数组,记录每一个位置的最大最小值,然后记录最大值与最小值的差值。

class Solution {
    public int maxProfit(int[] prices) {
        int a = -prices[0], b = 0;
        for(int i = 1; i < prices.length; i++) {
            a = Math.max(a, - prices[i]);
            b = Math.max(b, a + prices[i]);
        }
        return b;
    }
}

贪心

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

二、122. 买卖股票的最佳时机 II

题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-ii/description/
思路:这个和上一题的区别在于交易的次数不再限制,那么持有股票的逻辑就要修改一下,依然是之前就持有,和今天才持有,只不过今天才持有需要用之前就不持有时手中的余额减去今天的价格,即为今天才持有。
另外本题依然可以使用谈心来做,做的话,收集相邻两天的差值,进行累加,如果小于0,从新开始。

class Solution {
    public int maxProfit(int[] prices) {
        int[] dp = new int[2];
        dp[0] = -prices[0];
        for(int i = 1; i < prices.length; i++) {
            dp[0] = Math.max(dp[0], dp[1] - prices[i]);
            dp[1] = Math.max(dp[1], dp[0] + prices[i]);
        }
        return dp[1];
    }
}

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

题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iii/description/
思路:本题和上一题的区别在于,限定买卖次数,最多只能买卖2次,所以每一天有两种状态,即第一次买卖和第二次买卖,买卖又分为买与卖,状态还是之前就已经持有和今天才持有。第一次与第二次买入是有区别的,区别在于第一次买入的今天才持有是没有之前的不持有的状态的,或者说是0,而第二次买入的今天才持有是和第一次买入的不持有相关的。

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

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

题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-iv/description/
思路:前面的几道题目都是关于买卖次数的变体,本题也是,本题把买卖次数改为了最多k次,其实做法还是一样的,只不过需要把K次都遍历出来,之前次数少,比如2次都是手动写的。

class Solution {
    public int maxProfit(int k, int[] prices) {
        int[] dp = new int[2 * k];
        for(int i = 0; i < dp.length; i += 2) {
            dp[i] = -prices[0];        
        }
        for(int i = 1; i < prices.length; i++) {
            dp[0] = Math.max(dp[0], -prices[i]);
            dp[1] = Math.max(dp[1], dp[0] + prices[i]);
            for(int j = 2; j < dp.length; j += 2) {
                dp[j] = Math.max(dp[j], dp[j-1] - prices[i]);
                dp[j+1] = Math.max(dp[j+1], dp[j] + prices[i]);
            }
        }
        return dp[2*k-1];
    }     
}

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

题目链接:https://leetcode.cn/problems/best-time-to-buy-and-sell-stock-with-cooldown/description/
思路:本题特别之处在于,除了买卖股票之外还加了冷冻期了,卖了股票后要隔一天才能再买入,那此时买入依赖的前置条件正是两天前不持有时的状态,所以要往前依赖两天,所以注意初始化,单独初始化前两天即可。

class Solution {
    public int maxProfit(int[] prices) {
        int[][] dp = new int[prices.length][2];
        for(int i = 0; i < prices.length; i++) {
            if(i == 0) {
                dp[i][0] = -prices[i];
                continue;
            }
            if(i == 1) {
                dp[i][0] = Math.max(dp[i-1][0], -prices[i]);
                dp[i][1] = Math.max(dp[i-1][1], dp[i][0] + prices[i]);
                continue;
            }
            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][0] + prices[i]);
        }
        return dp[prices.length-1][1];
    }
}
  • 6
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

当年拼却醉颜红

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值