代码随想录算法训练营第三十五天| 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II、123.买卖股票的最佳时机III

写代码的第三十五天
买股票啦啦啦啦

121. 买卖股票的最佳时机

思路

动态规划的思路那是一点也没有的。看卡哥视频有点没明白,又看了一下代码随想录网站,看文字版了解了,说的已经非常清晰了,这里我自己有几处不太好理解的地方我记录一下。
解决问题1:dp数组怎么设置什么含义?dp数组设置成二维的,我觉得一维也是能做的,但是我没写出来,设置成二维的数组看题解倒是理解,但是要是自己想肯定想不出来。dp[i][0] 表示第i天持有股票所得最多现金;dp[i][1] 表示第i天不持有股票所得最多现金。
注意1:卡哥的文字讲解版中持有的意思是这个股票有,但不一定是当前这次买的,可以是之前就买了就有。
解决问题2:递推公式是什么?递推公式中,卡哥的解析也说的很明白,分为两种情况,当前i股票持有还是不持有。情况1:第i天持有股票,在注意1中我们解释了持有不见得是当前买的,也可能是之前买的,所以第一种可能是第i-1天就持有了股票,所以和第i-1天相同为dp[i-1][0],第二种可能是第i-1天没有,当天才买,在本题中买卖只有一次,所以如果当前买入了,那么就是从手里的钱为0开始,所以为-price[i](本题要求的是最大利润,当刚买入的时候初始钱为0,所以利润 是0-price[i]),所以情况1的最大利润是dp[i][0] = max(dp[i - 1][0], -prices[i]);情况2:第i天不持有股票,也是分两种可能,第一种可能是第i-1天就不持有,所以利润和第i-1天一样,为dp[i-1][1],第二种可能是第i天卖出股票,所以为第i-1天就持有股票所得现金加上卖出的第i天的价格,为dp[i - 1][0]+prices[i],所以情况2的递推公式为dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
解决问题3:dp数组初始化为什么?当前第i位都是由第i-1位决定的,所以需要初始化的是dp[0][0]和dp[0][1],dp[0][0]代表持有第0天的股票的最大现金=-price[0],dp[0][1]代表不持有第0天股票的最大现金=0。
解决问题4:遍历顺序?i是由i-1位决定的,所以是从0开始遍历,从左到右。
解决问题5:输出dp数组。
正确代码

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        dp = [[0 for _ in range(2)] for _ in range(len(prices))]
        dp[0][0] = -prices[0]
        dp[0][1] = 0
        for i in range(1,len(prices)):
            dp[i][0] = max(dp[i - 1][0], -prices[i])
            dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
        return dp[-1][1]

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

思路

本题和上一题的区别在于,上一题是只能进行一次买卖,本题可以多次买卖,但是每次买入之前都要把之前的卖掉!!!利润是求的总和利润
所以区别就在于递推公式这里,还是分两种情况,dp[i][0] 表示第i天持有股票所得最多现金;dp[i][1] 表示第i天不持有股票所得最多现金。
情况1:第i天持有股票,第一种可能是第i-1天就持有了股票,所以和第i-1天相同为dp[i-1][0],第二种可能是第i-1天没有,当天才买,在本题中买卖多次,所以如果当前买入了,那么就是把前面的股票抛售掉了,所以抛售的利润为第i-1天不持有股票所得的最多现金dp[i-1][1]开始再减去当前买股票的钱price[i],所以情况1的最大利润是dp[i][0] = max(dp[i - 1][0], dp[i-1][1]-prices[i]);
情况2:第i天不持有股票,也是分两种可能,第一种可能是第i-1天就不持有,所以利润和第i-1天一样,为dp[i-1][1],第二种可能是第i天卖出股票,所以为第i-1天就持有股票所得现金加上卖出的第i天的价格,为dp[i - 1][0]+prices[i],所以情况2的递推公式为dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0])
正确代码

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        dp = [[0 for _ in range(2)] for _ in range(len(prices))]
        dp[0][0] = -prices[0]
        dp[0][1] = 0
        for i in range(1,len(prices)):
            dp[i][0] = max(dp[i-1][0],dp[i-1][1]-prices[i])
            dp[i][1] = max(dp[i-1][1],dp[i-1][0]+prices[i])
        return dp[-1][1]

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

思路

本题可以进行两次买卖。
解决问题1:dp数组的含义是什么?dp[i][0]没有操作;dp[i][1]第一次持有股票;dp[i][2]第一次不持有股票;dp[i][3]第二次持有股票;dp[i][4]第二次不持有股票。
解决问题2:递推公式是什么?dp[i][0]不定义;
dp[i][1]分两种,第一种是第i-1次已经持股dp[i][1]=dp[i-1][1];第二种是第i-1次没持股,第i次才持股dp[i][1]=dp[i-1]0-prices[i],一定是选最大的,所以 max(dp[i-1][1], dp[i-1][0] - prices[i]);
dp[i][2]分两种,第一种是i-1的时候就不持有股票了dp[i-1][2];第二种是i-1时持有,第i次才卖掉所以dp[i][2] = dp[i-1][1]+ prices[i],也是要选最大的所以dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i]);
dp[i][3]分两种,最后的结果是dp[i][3]=max(dp[i-1][3], dp[i-1][2] - prices[i]);
同理,dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i]);
解决问题3:初始化为什么?dp[0][0] = 0;dp[0][1] = -prices[0];这两个和之前是一样的;dp[0][2]当天买入当天卖出所以=0;当前一次买入卖出结束后才有第二次的买入,可以看作是第一次都是当天买当天卖,那么第一次的利润就是0,所以dp[0][3] = -prices[0];同理dp[0][4] = 0;
解决问题4:遍历顺序?从前向后。
正确代码

class Solution:
    def maxProfit(self, prices: List[int]) -> int:
        dp = [[0 for _ in range(5)] for _ in range(len(prices))]
        dp[0][1] = -prices[0]
        dp[0][3] = -prices[0]
        for i in range(1,len(prices)):
            dp[i][1] = max(dp[i-1][1], dp[i-1][0] - prices[i])
            dp[i][2] = max(dp[i-1][2], dp[i-1][1] + prices[i])
            dp[i][3] = max(dp[i-1][3], dp[i-1][2] - prices[i])
            dp[i][4] = max(dp[i-1][4], dp[i-1][3] + prices[i])
        return dp[-1][-1]
  • 11
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值