LeetCode题练习与总结:买卖股票的最佳时机Ⅲ--123

168 篇文章 0 订阅
30 篇文章 0 订阅

一、题目描述

给定一个数组,它的第 i 个元素是一支给定的股票在第 i 天的价格。

设计一个算法来计算你所能获取的最大利润。你最多可以完成 两笔 交易。

注意:你不能同时参与多笔交易(你必须在再次购买前出售掉之前的股票)。

示例 1:

输入:prices = [3,3,5,0,0,3,1,4]
输出:6
解释:在第 4 天(股票价格 = 0)的时候买入,在第 6 天(股票价格 = 3)的时候卖出,这笔交易所能获得利润 = 3-0 = 3 。
     随后,在第 7 天(股票价格 = 1)的时候买入,在第 8 天 (股票价格 = 4)的时候卖出,这笔交易所能获得利润 = 4-1 = 3 。

示例 2:

输入:prices = [1,2,3,4,5]
输出:4
解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5-1 = 4 。   
     注意你不能在第 1 天和第 2 天接连购买股票,之后再将它们卖出。   
     因为这样属于同时参与了多笔交易,你必须在再次购买前出售掉之前的股票。

示例 3:

输入:prices = [7,6,4,3,1] 
输出:0 
解释:在这个情况下, 没有交易完成, 所以最大利润为 0。

示例 4:

输入:prices = [1]
输出:0

提示:

  • 1 <= prices.length <= 10^5
  • 0 <= prices[i] <= 10^5

二、解题思路

这个问题是典型的动态规划问题。我们需要找到最大利润,但这次我们最多可以进行两笔交易。我们可以用动态规划来跟踪在每一天结束时,我们能获得的最大利润。

我们需要定义以下状态变量:

  • buy1:第一次购买股票后的最大利润。
  • sell1:第一次卖出股票后的最大利润。
  • buy2:第二次购买股票后的最大利润。
  • sell2:第二次卖出股票后的最大利润。

初始状态:

  • buy1 = -prices[0](我们在第一天买入股票)
  • sell1 = 0(我们还没有卖出股票)
  • buy2 = -prices[0](我们在第一天买入股票,然后再次买入)
  • sell2 = 0(我们还没有进行第二次卖出)

对于每一天,我们需要更新这些状态变量:

  • buy1 = max(buy1, -prices[i])(我们保持当前的最大亏损或在新低价时买入)
  • sell1 = max(sell1buy1 + prices[i])(我们保持当前的最大利润或在高价时卖出)
  • buy2 = max(buy2sell1 - prices[i])(我们在第一次卖出后,在低价时再次买入)
  • sell2 = max(sell2buy2 + prices[i])(我们在第二次买入后,在高价时卖出)

最终答案是sell2

三、具体代码

class Solution {
    public int maxProfit(int[] prices) {
        if (prices == null || prices.length == 0) {
            return 0;
        }

        int buy1 = -prices[0], sell1 = 0;
        int buy2 = -prices[0], sell2 = 0;

        for (int i = 1; i < prices.length; i++) {
            buy1 = Math.max(buy1, -prices[i]);
            sell1 = Math.max(sell1, buy1 + prices[i]);
            buy2 = Math.max(buy2, sell1 - prices[i]);
            sell2 = Math.max(sell2, buy2 + prices[i]);
        }

        return sell2;
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 我们可以看到,代码中有一个循环,这个循环会遍历一次给定的数组prices
  • 在循环内部,我们执行了四个基本操作,每个操作都是常数时间的操作,如比较和赋值。
  • 因此,循环的每次迭代都是常数时间的,即O(1)。
  • 由于循环执行了prices.length - 1次迭代(从索引1开始到prices.length - 1),所以总的时间复杂度是O(n),其中n是数组prices的长度。
2. 空间复杂度
  • 我们在代码中定义了四个整型变量buy1sell1buy2sell2来存储每一步的最大利润状态。
  • 这些变量使用的空间是常数大小的,与输入数组prices的大小无关。
  • 因此,不管输入数组prices有多大,我们所使用的额外空间都是固定的,即O(1)。

综上所述,代码的时间复杂度是O(n),空间复杂度是O(1)。

五、总结知识点

1. 基本编程概念

  • 变量定义:代码中定义了四个整型变量来存储买入和卖出的最大利润。
  • 循环结构:使用for循环来遍历数组prices中的每个元素。

2. 数组操作

  • 访问数组元素:通过索引i访问数组prices中的元素。

3. 数学运算

  • 最大值比较:使用Math.max()函数来比较并保留最大值。

4. 算法思想

  • 动态规划:使用动态规划的思想来逐步计算最大利润,而不是暴力搜索所有可能的交易组合。

5. 动态规划状态定义

  • buy1sell1:分别代表第一次买入和卖出股票后的最大利润。
  • buy2sell2:分别代表第二次买入和卖出股票后的最大利润。

6. 边界条件处理

  • 检查输入数组是否为空或长度为0,如果是,则直接返回

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

  • 9
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一直学习永不止步

谢谢您的鼓励,我会再接再厉的!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值