力扣算法学习day35-3

文章目录

  • 力扣算法学习day35-3
    • 309-最佳买卖股票时机含冷冻期
      • 代码实现 - 补充中午 - 另一种dp解法
    • 714-买卖股票的最佳时机含手续费 (完全版)
      • 题目
      • 代码实现---在之前的代码基础上加上了dp方法和dp的一维优化
        • 已复习 代码随想录-股票问题总结篇

力扣算法学习day35-3

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

代码实现 - 补充中午 - 另一种dp解法

代码直接粘贴整个了。

class Solution {
    // 先自己尝试做,似乎做出来了什么奇怪的题解。
    // public int maxProfit(int[] prices) {
    //     // dp 速度 1ms
    //     // 状态:
    //     // dp[i][0]:第i天为 持有状态时  的最大利润
    //     // dp[i][1]:第i天为 未持有状态  的最大利润
    //     // 持有状态分为当前买入或之前持有,当前买入需要考虑多次卖出的利润以及当前卖必须要隔一天,
    //     // 我想的是既然卖出要隔一天,那卖出有利润的情况 就是隔两天就对了哇。
    //     // 故迭代公式: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-1][0] + prices[i])
    //     // 额,通过了,看了哈代码随想录的,他分了四种状态,和我这个有些不一样。

    //     int[][] dp = new int[prices.length][2];

    //     // 初始化
    //     dp[0][0] = -prices[0];
    //     dp[0][1] = 0;

    //     // 1,2,5,0,2
    //     // -1,-1,1,2
    //     //  0,1,4,4,4
    //     for(int i = 1;i < prices.length;i++){
    //         if(i < 2){// 这里主要考虑长度在小于3的情况下,多次买入根本就没得意义,就最多一次买入。
    //             dp[i][0] = Math.max(dp[i-1][0],-prices[i]);
    //         } else{
    //             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-1][0] + prices[i]);
    //     }

    //     return dp[prices.length-1][1];
    // }

    // 代码随想录思路
    public int maxProfit(int[] prices) {
        // 前言:代码随想录的方法分成了四种情况,个人觉得不容易想到,但是,如果想到了,
        // 我感觉这种状态的分割对于每个状态的依赖关系会更加清晰一些。
        // dp[i][0]:第i天 持有股票状态  的最大值
        // 未持有分为两种情况:
        // dp[i][1]:第i天 两天前卖出    的最大值(即已经度过冷冻期)
        // dp[i][2]:第i天 当前这天卖出  的最大值
        // dp[i][3]:第i天 冻结期状态    的最大值
        // 第一种情况,可以是之前就买入了,可以是当天买入,当天买入分为前一天是冻结期,或
        // 两天前已近卖出了。即已经过了冻结期了。
        // dp[i][0] = Math.max(dp[i-1][0],Math.max(dp[i-1][3]-prices[i],dp[i-1][1]-prices[i]));
        // 第二种情况,两天前卖出,即已经度过冷冻期,要么是前一天就已经保持这个状态,要么是前一天是冷冻期。
        // dp[i][1] = Math.max(dp[i-1][1],dp[i-1][3]);
        // 第三种情况,当天卖出,那就只有前一天为持有状态的情况了。
        // dp[i][2] = dp[i-1][0] + prices[i];
        // 第四种情况,冷冻期,冷冻期只有在前一天卖出的情况才出现。
        // dp[i][3] = dp[i-1][2];

        int[][] dp = new int[prices.length][4];

        // 初始化
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        dp[0][2] = 0;
        dp[0][3] = 0;

        for(int i = 1;i < prices.length;i++){
            dp[i][0] = Math.max(dp[i-1][0],Math.max(dp[i-1][3]-prices[i],dp[i-1][1]-prices[i]));
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][3]);
            dp[i][2] = dp[i-1][0] + prices[i];
            dp[i][3] = dp[i-1][2];
        }

        return Math.max(Math.max(dp[prices.length-1][1],dp[prices.length-1][2]),dp[prices.length-1][3]);
    }
}

714-买卖股票的最佳时机含手续费 (完全版)

题目

力扣算法学习day35-3_第1张图片

力扣算法学习day35-3_第2张图片

代码实现—在之前的代码基础上加上了dp方法和dp的一维优化

class Solution {
    // public int maxProfit(int[] prices, int fee) {
    //     // 贪心 速度5ms
    //     // 局部最优:找每个小阶段最大利润。  --> 全局最优:总利润最大。
    //     // 局部:先将第一个假设为最小值,后面需要找的是当前值大于最小值超过fee的值,在找到第一个这个值之前
    //     // 还需要将每次不符合的值与最小值进行比较,确保在找当前值大于最小值超过fee的值的时候最小值是前面那些
    //     // 数中的最小值,然后当找到第一个符合当前值大于最小值超过fee的值后,还需要考虑这个最大值会不会是最
    //     // 大利润,因为后面还有可能有更大的值。因为有续费的存在,如果先卖了,会导致无法获得最大的利润,所以
    //     // 当找到第一个符合当前值大于最小值超过fee的值后,需要将这个值赋给最大值(引用),然后下一轮的时候再判断
    //     // 下一轮的当前值是否比最大值小fee-1的大小,如果是,那么说明最大值可以卖了,就算后面有更大的值,那么
    //     // 它们也是等效或更大的利润,比如:前面的利润是 最大值-最小值-fee,然后这个截止的值是需要比最大值小fee-1
    //     // 以上,那么 它 <= 最大值-fee,然后后面假设有更大的值,比如为 最大值+1 就更大,那么,可得:
    //     // 最大值+1 - 最小值 - fee <= 最大值-最小值-fee + (最大值+1 - 它 - fee),故可行。然后之后的同理继续即可。
    //     int minValue = prices[0];// 由题可知,prices长度大于等于1.故直接选第一个为最初最小值。
    //     int maxValue = 0;
    //     int sum = 0;// 记录最大利润。

    //     for(int i = 1;i < prices.length;i++){
    //         if(prices[i] <= maxValue - fee){
    //             sum += maxValue - minValue - fee;
    //             minValue = prices[i];
    //             maxValue = 0;
    //         }
    //         if(prices[i] - minValue > fee){
    //             maxValue = Math.max(maxValue,prices[i]);
    //         } else{
    //             minValue = Math.min(minValue,prices[i]);
    //         }
    //     }

    //     if(maxValue != 0){
    //         sum += maxValue - minValue - fee;
    //     }

    //     return sum;
    // }

    // 代码随想录Java模板贪心,速度 3ms
    // 主要优化是在第一个最高值及最高值后面的考虑更精妙,但是不一定想得到。
    // public int maxProfit(int[] prices, int fee) {
    //     int buy = prices[0] + fee;
    //     int sum = 0;
    //     for (int p : prices) {
    //         if (p + fee < buy) {
    //             buy = p + fee;
    //         } else if (p > buy){
    //             sum += p - buy;
    //             buy = p;
    //         }
    //     }
    //     return sum;
    // }

    // dp:动态规划 速度 18ms,速度慢一点,但是思路上如果学过dp会感觉这种方法更快想到且更简单。
    public int maxProfit(int[] prices, int fee) {
        // dp[i][0]:表示第i天 持有状态      的最大值
        // dp[i][1]:表示第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] - fee);

        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][0],dp[i-1][1] - prices[i]);
            dp[i][1] = Math.max(dp[i-1][1],dp[i-1][0] + prices[i] - fee);
        }

        return dp[prices.length-1][1];
    }

    // dp:代码随想录下面给出的一维数组优化 速度:6ms
    // public int maxProfit(int[] prices, int fee) {
    // int[] dp = new int[2];
    // dp[0] = -prices[0];
    // dp[1] = 0;
    // for (int i = 1; i <= prices.length; i++) {
    //   dp[0] = Math.max(dp[0], dp[1] - prices[i - 1]);
    //   dp[1] = Math.max(dp[1], dp[0] + prices[i - 1] - fee);
    // }
    // return dp[1];
    // }
}
已复习 代码随想录-股票问题总结篇

股票篇,有点繁杂,需要多举例理解、多分析状态情况、弄清楚状态之间的依赖关系、还有每个状态分析的情况是否无后效性等等等。

你可能感兴趣的:(算法刷题,算法,leetcode,动态规划)