动态规划Day12(股票问题终结,有点疑惑)

目录

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

看到题目的第一想法               

看到代码随想录之后的想法

自己实现过程中遇到的困难

714.买卖股票的最佳时机含手续费

看到题目的第一想法               

看到代码随想录之后的想法

自己实现过程中遇到的困难


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

力扣题目链接(opens new window)

给定一个整数数组,其中第 i 个元素代表了第 i 天的股票价格 。

设计一个算法计算出最大利润。在满足以下约束条件下,你可以尽可能地完成更多的交易(多次买卖一支股票):

  • 你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。
  • 卖出股票后,你无法在第二天买入股票 (即冷冻期为 1 天)。

示例:

  • 输入: [1,2,3,0,2]
  • 输出: 3
  • 解释: 对应的交易状态为: [买入, 卖出, 冷冻期, 买入, 卖出]
看到题目的第一想法
               

        回忆一下之前的股票问题是怎么做的?

        dp[i][0] 买入股票的最大现金

                        则为  之前买入的,当天买入的(用前一天的冷冻期来-)

                        Math.max(dp[i-1][0],dp[i-1][3]-prices[i]);

        dp[i][1] 卖出股票的最大现金

                        Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);

        我考虑加上一个 dp[i][3] 当天若为冷冻期的现金 

                        则直接为dp[i-1][1],不管是不是冷冻期都默认为dp[i-1][1]

        

看到代码随想录之后的想法

             代码随想录分析思路更加详细

         dp[i][j]:j有四种情况

         一. dp[i][0] 买入股票的最大现金

                1之前买入 dp[i-1][0]

                2当天买入

                        1 当天之前是冷冻期

                                dp[i-1][3]-price[i]  

                      2 当天之前不是冷冻期

                               dp[i-1][1]-price[i]

             二. dp[i][1] 之前卖出的最大现金

                1 当天之前是冷冻期

                        dp[i-1][3]

                2 当天之前不是冷冻期

                        dp[i-1][1]

              三.dp[i][2] 当天卖出的最大现金

                       dp[i-1][0]+prices[i]

              四. dp[i][3] 冷冻期的最大现金代码

                        则为前一天卖出的最大现金 dp[i-1][2]

        

        打印dp数组时,应该为 Math.max(dp[i][2],dp[i][3],dp[i][4])

自己实现过程中遇到的困难

        卡哥的做法:需要理清卡哥给的关系

        打印dp的值需要注意

class Solution {
    public int maxProfit(int[] prices) {
        /*
        //买入,卖出,冷冻期,买入,卖出,冷冻期
        //题意是要算出最大利润,但是需要尽可能地完成多的交易?
        //定义dp数组和每个下标的含义
        //冷冻期的最大金额?
        // dp[i][j] dp[i][0] 买入的最大金额,
        // dp[i][1]卖出的最大金额,
        // dp[i][2]冷冻期的最大金额
        //定义递推公式
        //冷冻期的最大金额-price[i]
        //dp[i][0] 买入时的最大值Math。max(dp[i-1][0],dp[i-1][2]-price[i]);
        //dp[i][1] 卖出时的最大值Math。max(dp[i-1][1],dp[i-1][0]+price[i]);
        //dp[i][2] 冷冻期 dp[i-1][1]
        //dp数组初始化
        //确定遍历顺序
        //从左至右
        //举例推导dp数组
        int[][] dp = new int[prices.length][3];
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        dp[0][2] = 0;
        for(int i=1;i<prices.length;i++){
            dp[i][0] = Math.max(dp[i-1][0],dp[i-1][2]-prices[i]);
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
            dp[i][2] = dp[i-1][1];
        }
        return dp[prices.length-1][1];*/
        //我的做法不够细致,有些地方模棱两可,没有卡哥思路写的那么清晰
        //卡哥思路:
        //一天存在的状态
        //1 买入股票
        //  1 当天买入,前一天为冷冻期 dp[i-1][3]+prices[i]
        //  2 当天买入,前一天不为冷冻期 dp[i-1][1]+prices[i]
        //  3 之前就买入 dp[i-1][0]
        //2 之前卖出股票
        //  1 若当天之前为冷冻期
        //  dp[i-1][3]
        //  2 若当天之前不为冷冻期
        //  dp[i-1][1]
        //3 当天卖出股票
        //  dp[i-1][0]+prices[i]
        //4 当天为冷冻期
        //  dp[i-1][2]
        //初始化
        //dp[0][0] = -price[i] 其他都为0,看dp的递推公式,应该都赋值为0
        //遍历顺序,从前往后
        int[][] dp = new int[prices.length][4];
        dp[0][0] = -prices[0];
        for(int i=1;i<prices.length;i++){
            //前一天为冷冻期,前一天不为冷冻期
            dp[i][0] = Math.max(Math.max(dp[i-1][3]-prices[i],dp[i-1][1]-prices[i]),dp[i-1][0]);
            //之前卖出,要考虑前一天是冷冻期or不是冷冻期
            dp[i][1] = Math.max(dp[i-1][3],dp[i-1][1]);
            //当天卖出
            dp[i][2] = dp[i-1][0]+prices[i];
            //当天为冷冻期,则前一天卖出
            dp[i][3] = dp[i-1][2];
        }
        
        //return 应该是123 之前写成了012 报错
        return Math.max(dp[prices.length-1][3],Math.max(dp[prices.length-1][1],dp[prices.length-1][2]));
    }
}

714.买卖股票的最佳时机含手续费

力扣题目链接(opens new window)

给定一个整数数组 prices,其中第 i 个元素代表了第 i 天的股票价格 ;非负整数 fee 代表了交易股票的手续费用。

你可以无限次地完成交易,但是你每笔交易都需要付手续费。如果你已经购买了一个股票,在卖出它之前你就不能再继续购买股票了。

返回获得利润的最大值。

注意:这里的一笔交易指买入持有并卖出股票的整个过程,每笔交易你只需要为支付一次手续费。

示例 1:

  • 输入: prices = [1, 3, 2, 8, 4, 9], fee = 2
  • 输出: 8

解释: 能够达到的最大利润:

  • 在此处买入 prices[0] = 1
  • 在此处卖出 prices[3] = 8
  • 在此处买入 prices[4] = 4
  • 在此处卖出 prices[5] = 9
  • 总利润: ((8 - 1) - 2) + ((9 - 4) - 2) = 8.

注意:

  • 0 < prices.length <= 50000.
  • 0 < prices[i] < 50000.
  • 0 <= fee < 50000.
看到题目的第一想法
               

        回忆一下之前的股票问题是怎么做的?

        dp[i][0] 买入股票的最大现金 减去相关的手续费即可

                        Math.max(dp[i-1][0],dp[i-1][3]-prices[i]-fee);

        dp[i][1] 卖出股票的最大现金

                        Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);

         1 应该怎么初始化?

        我的初始化是

        dp[0][0] = -prices[0]-fee

        dp[0][1] = dp[0][0]+prices[0](是有问题的)

        

看到代码随想录之后的想法

        代码随想录分析思路更加详细

         dp[i][j]:情况分析

        

        dp[i][0] 买入股票的最大现金

                        Math.max(dp[i-1][0],dp[i-1][3]-prices[i]);

        dp[i][1] 卖出股票的最大现金 加上相关的手续付费

                        Math.max(dp[i-1][1],dp[i-1][0]+prices[i]+fee);

        只需要初始化dp[0][0]=-prices[0]

        打印dp数组时,为什么是Math.max(dp[prices.length][0],dp[prices.length[1]]);

自己实现过程中遇到的困难

               不理解

                1初始化:dp[0][1]为何不用初始化

                2打印 :为何打印两个值?

 1:dp[0][1]对应的是第一天不持股的最佳状态,而不持股有两种可能性,可能是从开始就没有买过,也可能是买入又卖出,因此这里最佳应该是没有买过是 0,所以不用额外初始化


2:一般股票买卖的话,不持股状态下肯定比持有股票所得的现金多,没有问题。这个题应该是考虑到 fee 的存在,如果有一个 fee 特别大,那么可能就卖出不如不卖持有的现金多了,例如用例为 [1], 100 
但是因为不持股状态有不买不卖(也就是 0)这种情况的存在,使得最后的递推公式肯定不会推出负值,所以直接返回 不持股状态 就可以,没有任何问题

class Solution {
    public int maxProfit(int[] prices, int fee) {
        //需要算进去一个手续费用
        //买的时候需要加上手续费
        //确定dp数组以及每个下标的含义
        //dp[i][0] 买入股票的最大值 Math.max(dp[i-1][1]-prices[i]-2,dp[i-1][0]);
        //dp[i][1] 卖出股票的最大值 Math.max(dp[i-1][1],dp[i-1][0]+price[i]);
        //确定递推公式
        //dp数组初始化
        //dp[i][0]=-price[0];
        //确定遍历顺序
        //从前往后
        
        int[][] dp = new int[prices.length][2];
        dp[0][0]=-prices[0]-fee;
        dp[0][1]=0;
        for(int i=1;i<prices.length;i++){
            dp[i][0] = Math.max(dp[i-1][1]-prices[i]-fee,dp[i-1][0]);
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]+prices[i]);
        }
        return Math.max(dp[prices.length-1][1],dp[prices.length-1][0]);
        
        /*
        int[][] dp = new int[prices.length][2];
        dp[0][0]=-prices[0];
        for(int i=1;i<prices.length;i++){
            dp[i][0] = Math.max(dp[i-1][1]-prices[i],dp[i-1][0]);
            //卡哥做法,卖出股票才付手续费 手续费为fee 之前写成了2
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0]+prices[i]-fee);
        }
        return Math.max(dp[prices.length-1][1],dp[prices.length-1][0]);*/
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值