算法训练(leetcode)二刷第三十五天 | *121. 买卖股票的最佳时机、*122. 买卖股票的最佳时机 II、*123. 买卖股票的最佳时机 III

刷题记录

  • [*121. 买卖股票的最佳时机](#*121. 买卖股票的最佳时机)
  • [*122. 买卖股票的最佳时机 II](#*122. 买卖股票的最佳时机 II)
  • [*123. 买卖股票的最佳时机 III](#*123. 买卖股票的最佳时机 III)

*121. 买卖股票的最佳时机

leetcode题目地址

贪心

记录最低价格作为买入价格,并用当前价格减去最低价格获得利润。

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( 1 ) O(1) O(1)

java 复制代码
// java
class Solution {
    public int maxProfit(int[] prices) {

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

*动态规划

首先需要理清楚dp数组的含义,dp数组中存储的是持有或不持有的利润,而不是当天买入或卖出的利润。

dpi0表示第i天持有股票的利润,可以之前买入也可以当天买入,取二者最大值保留即可,即,dpi0 = max(dpi-10, -pricesi)

dpi1表示第i天不持有股票的利润,可以之前卖出也可以当天卖出,同样取二者最大值保留,即,dpi1 = max(dpi-11, dpi-10+pricesi)

java 复制代码
// java
class Solution {
    public int maxProfit(int[] prices) {
        int n = prices.length;
        int[][] dp = new int[n][2];
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        for(int i=1; i<n; i++){
            // 持有
            dp[i][0] = Math.max(dp[i-1][0], -prices[i]);
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]+prices[i]);
        }
        return dp[n-1][1];
    }
}

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

leetcode题目地址

使用二维dp数组,dpi0表示第i天持有股票的价值,dpi1表示第i天不持有股票的价值。

  • dpi0 = Math.max(dpi-10, dpi-11-pricesi);
    第i天持有股票的价值 = max(前一天就持有股票的价值,当天买入股票)
  • dpi1 = Math.max(dpi-11, dpi-10+pricesi);
    第i天不持有股票的价值 = max(前一天就不持有股票的价值,当天卖出股票)

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

java 复制代码
// java
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][0], dp[i-1][1]-prices[i]);
            dp[i][1] = Math.max(dp[i-1][1], dp[i-1][0]+prices[i]);
        }
        return dp[prices.length-1][1];
        
    }
}

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

leetcode题目地址

使用二维dp数组来记录每天的状态下的最大收益,即:

dpij表示第i天的第j个状态的最大收益。

共有五个状态

  • 0 未操作(可省略)
  • 1 第一次持有
  • 2 第一次不持有
  • 3 第二次持有
  • 4 第二次不持有

本题的难点在于初始化。

本题要求每次购入之前不许持有股票,也就是卖出后才能重新购入。

因此,初始化如下:

  • dp00表示第0天不操作,收益为0.
  • dp01表示第0天第一次持有(即当天第一次买入),收益为-prices0
  • dp02表示第0天第一次不持有(即当天第一次卖出),收益为dp01+prices0,也就是0
  • dp03表示第0天第二次持有(即当天第二次买入),收益为dp02-prices0,也就是-prices0
  • dp04表示第0天第二次不持有(即当天第二次卖出),收益为dp02+prices0,也就是0

dp03和dp04比较难想到,因为它是在同一天进行的两次操作。

每一个状态的更新,依赖于前一个状态的结果。也就是持有的状态下才能卖出、不持有的状态下才能买入。

dpi0可以忽略不使用,因为在整体状态转移中和这个状态没有关系。(或者可以理解为第一次买入是在未操作的状态上进行的)

最大的时候一定是卖出的状态,而两次卖出的状态现金最大一定是最后一次卖出。可以这么理解:如果第一次卖出已经是最大值了,那么我们可以在当天立刻买入再立刻卖出。所以dpi4已经包含了dpi2的情况。也就是说第二次卖出手里所剩的钱一定是最多的。

时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)

java 复制代码
// java
class Solution {
    public int maxProfit(int[] prices) {
        int[][] dp = new int[prices.length][5];
        dp[0][1] = -prices[0];
        dp[0][3] = -prices[0];
        
        for(int i=1; i<prices.length; i++){
            dp[i][1] = Math.max(dp[i-1][1], -prices[i]);
            
            dp[i][2] = Math.max(dp[i-1][2], dp[i-1][1]+prices[i]);
            
            dp[i][3] = Math.max(dp[i-1][3], dp[i-1][2]-prices[i]);
            
            dp[i][4] = Math.max(dp[i-1][4], dp[i-1][3]+prices[i]);
        }

        return dp[prices.length-1][4];
    }
}
相关推荐
kisshyshy7 小时前
🍦 雪糕、食堂、火车厢:三幅漫画吃透栈、队列与链表
javascript·算法
猿人谷14 小时前
不只是 CPU 阈值:STAR 如何用 GAT + Transformer 做容器级自动扩缩容?
人工智能·算法
复杂网络15 小时前
Stable Diffusion 视觉大模型微调技术深度调研
算法
复杂网络15 小时前
基于 Stable Diffusion 架构的视觉大模型代表性工作与原理深度解析
算法
MrZhao40016 小时前
Agent Loop 如何用 Hook 扩展:权限、日志与工具拦截
算法
MrZhao40016 小时前
Agent 为什么需要 Skills:别把所有知识都塞进 system prompt
算法
JieE2122 天前
LeetCode 101. 对称二叉树|JS 递归 + 迭代双解法,彻底搞懂镜像判断
javascript·算法
JieE2123 天前
LeetCode 56. 合并区间|超清晰 JS 图解思路,面试高频区间题
javascript·算法·面试
Jack203 天前
HarmonyOS开发中错误处理策略:网络异常统一处理
算法
小小杨树3 天前
读懂色彩:拍照调色不再难
算法·计算机视觉·配色