代码随想录day 48 动态规划 买卖股票的最佳时机

代码随想录day 48 动态规划 买卖股票的最佳时机

题121 买卖股票的最佳时机1

1,暴力解法(会超时),贪心算法可以解答此题。
2,动态规划如何解决呢?
3,定义dp数组:第i天买还是不买,两个状态。
* dp[i][0] 表示第i天持有股票的状态下手头的最大现金。(可以理解为最开始手头现金为0)
* dp[i][1]表示第i天不持有股票的状态下手头的最大现金。
4,确定递推公式:
两种情况,(1)第i 天持有股票,那么这个股票可能是之前就买入的,也可能是当天买入的, 如果是之前就买入的则dp[i] [0]= dp[i - 1] [0](当天不进行任何操作,则手里的现金保持不变); 这个股票也有可能是当天买入的,此时dp[i][0] = - prices[i], 买入股票后手里的现金为负数,因为初始认为为0。dp[i]取两者的最大值。
(2)类似的,第i天不持有股票,那么可以是之前就卖掉了股票,也可能是当天卖掉了股票(此时前一天一定是持有的状态)。dp[i][1] = max(dp[i - 1][1]) , dp[i - 1][0] + prices[i])。

5,将dp数组打印并分析之后其实dp[i][0]就是记录的买入的最低价,dp[i][1]记录的是卖出的最大利润。
6,一个困惑的问题:会不会买卖多次,其实最后记录的结果一定是低买高出的,但在遍历的过程中计算了每次的买入和卖出,但保留到最后的其实一直是最低价的买入和最大差价的卖出
因为比如[7, 1, 5, 3, 6, 4],初始化dp[0][0] = -7, dp[0][1] = 0, 第二天遇到了最低价格,此时dp[1][0] = max(-7, -1) = -1, 再接着往后遍历的时候如果没有遇到价格低于1的,dp[i][0]会一直延续为-1,(相当于保留着在价格为1时买入的状态)。对于卖出,比如第二天dp[1][1] = max(-7 + 1 , 0) = 0(延续第一天的不持有状态,因为如果当天卖出现金为-6,比0小), 到了第三天 dp[2][1] = max(-1 + 5, 0)=4 , -1是前一天持有股票的现金(要卖出必须取前面持有的状态),第4天股票价格为3,dp[3][1] = max(-1 + 3, 4) = 4,注意此时4是延续之前的状态,说明第4天并不能真正卖股票。遍历到后面遇到股票价格更好的时候会更新不持有的现金,因此保留下来的一定是最大的利润差,而且不会出现多次买卖的问题(除非最低买入价和最高卖出价重复出现)
其实当天持有股票的状态已经可以反应出来不会重复买卖了,因为如果买入则dp[i][0] = - prices[i], 用初始0直接减当前的价格的。

class Solution {
    //贪心算法:找到左边最小值,取利润最大值。
    // public int maxProfit(int[] prices) {
    //     if(prices.length == 1) return 0;
    //     int min = prices[0];
    //     int maxProfit = 0;
    //     for(int i = 1; i < prices.length; i++) {
    //         if(prices[i] >= min) {
    //             maxProfit = Math.max(prices[i] - min, maxProfit);
    //         }
    //         min = Math.min(min, prices[i]);
    //     }
    //     return maxProfit;
    // }

    //动态规划算法
    public int maxProfit(int[] prices) {
        int[][] dp = new int[prices.length][2];
        dp[0][0] = -prices[0]; //表示初始持有股票,代表第一天就要买入,手里的现金就是-prices[0].
        dp[0][1] = 0; //表示初始不持有股票,手里的现金为0
        for(int i = 1; i < prices.length; i++) {
            dp[i][0] = Math.max(-prices[i], dp[i - 1][0]); //第i天持有股票,手里现金的最大值。
            dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]); //第i天不持有股票,手里现金的最大值。
        }
        return dp[prices.length - 1][1];
    }
}

题122 买卖股票的最佳时机2

1,本题和121题的区别在于允许多次买卖,保持不变的是手上只能有一只股票存在。
2,那么递推公式的区别在于持有股票时买入的情况,也就是dp[i][0]的其中一种情况,如果在第i天买入,则买入时手头的现金不再一直是初始的0,而应该是之前不持有股票时的最大现金dp[i - 1][1] , 因此dp[i][0] = max(dp[i - 1][1] - prices[i], dp[i - 1][0])。(上一题是0-prices[i],其实这里就是区别单次买卖和多次买卖的地方)。

class Solution {

    //动态规划
    public int maxProfit(int[] prices) {
        int[][] dp = new int[prices.length][2];
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        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][1], dp[i - 1][0] + prices[i]);
        }
        return dp[prices.length - 1][1];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值