LeetCode Day51

46 阅读4分钟

121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。 你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。 返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

示例 1: 输入:[7,1,5,3,6,4] 输出:5 解释:在第 2 天(股票价格 = 1)的时候买入,在第 5 天(股票价格 = 6)的时候卖出,最大利润 = 6-1 = 5 。 注意利润不能是 7-1 = 6, 因为卖出价格需要大于买入价格;同时,你不能在买入前卖出股票。 示例 2: 输入:prices = [7,6,4,3,1] 输出:0 解释:在这种情况下, 没有交易完成, 所以最大利润为 0。

思路

1. 确定dp数组(dp table)以及下标的含义

定义一个一维数组dp,其中dp[i]表示第i天卖出股票所能获得的最大利润。

2. 确定递推公式

其中,minPrice是到第i天为止的最低股票价格。

3. dp数组如何初始化

dp[0]应初始化为0,因为第一天卖出股票利润为0。

4. 确定遍历顺序

从第二天开始遍历,即从i = 1开始,直到i = n-1,其中n是数组prices的长度。

5. 举例推导dp数组

prices = [7, 1, 5, 3, 6, 4]为例,dp数组初始化为[0, 0, 0, 0, 0, 0]

  • 第2天(i = 1):minPrice = 1dp[1] = max(0, 1 - 1) = 0
  • 第3天(i = 2):minPrice = 1dp[2] = max(0, 5 - 1) = 4
  • 第4天(i = 3):minPrice = 1dp[3] = max(4, 3 - 1) = 4
  • 第5天(i = 4):minPrice = 1dp[4] = max(4, 6 - 1) = 5
  • 第6天(i = 5):minPrice = 1dp[5] = max(5, 4 - 1) = 5

最终,dp[n-1] = dp[5] = 5,即最大利润为5。

题解

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if (n == 0) return 0;
        vector<int> dp(n, 0);
        int minPrice = prices[0];
        
        for (int i = 1; i < n; ++i) {
            minPrice = min(minPrice, prices[i]);
            dp[i] = max(dp[i-1], prices[i] - minPrice);
        }
        
        return dp[n-1];
    }
};

优化思路

1. 确定dp数组(dp table)以及下标的含义

  • dp[i][0]:第i天持有股票所能获得的最大利润。
  • dp[i][1]:第i天不持有股票所能获得的最大利润。

2. 确定递推公式

  • dp[i][0] = max(dp[i - 1][0], -prices[i]):第i天持有股票的最大利润是前一天持有股票的最大利润(即没有卖出)和第i天买入股票两者之间的较大值。
  • dp[i][1] = max(dp[i - 1][1], prices[i] + dp[i - 1][0]):第i天不持有股票的最大利润是前一天不持有股票的最大利润(即没有买入)和第i天卖出股票两者之间的较大值。

3. dp数组如何初始化

  • dp[0][0] = -prices[0]:第0天买入股票,所以利润为-prices[0]
  • dp[0][1] = 0:第0天不买入也不卖出,利润为0。

4. 确定遍历顺序

从第1天开始遍历,直到最后一天。

5. 举例推导dp数组

prices = [7, 1, 5, 3, 6, 4]为例,

  • 第1天:dp[1][0] = max(-7, -1) = -1dp[1][1] = max(0, 1 + (-7)) = 0
  • 第2天:dp[2][0] = max(-1, -5) = -1dp[2][1] = max(0, 5 + (-1)) = 4
  • 第3天:dp[3][0] = max(-1, -3) = -1dp[3][1] = max(4, 3 + (-1)) = 4
  • 第4天:dp[4][0] = max(-1, -6) = -1dp[4][1] = max(4, 6 + (-1)) = 5
  • 第5天:dp[5][0] = max(-1, -4) = -1dp[5][1] = max(5, 4 + (-1)) = 5

最终,dp[len - 1][1] = dp[5][1] = 5,即最大利润为5。 这种方法更加通用,适用于更复杂的股票交易问题,例如允许多次买入和卖出,有交易费用等。

优化题解

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if (n == 0) return 0;
        vector<vector<int>> dp(n, vector<int>(2));
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        
        for (int i = 1; i < n; ++i) {
            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[n - 1][1];
    }
};

这种解法更加通用,并适用于下一题

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

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。 在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。 返回 你能获得的 最大 利润 。

示例 1: 输入:prices = [7,1,5,3,6,4] 输出:7 解释:在第 2 天(股票价格 = 1)的时候买入,在第 3 天(股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。 随后,在第 4 天(股票价格 = 3)的时候买入,在第 5 天(股票价格 = 6)的时候卖出, 这笔交易所能获得利润 = 6 - 3 = 3 。 总利润为 4 + 3 = 7 。 示例 2: 输入:prices = [1,2,3,4,5] 输出:4 解释:在第 1 天(股票价格 = 1)的时候买入,在第 5 天 (股票价格 = 5)的时候卖出, 这笔交易所能获得利润 = 5 - 1 = 4 。 总利润为 4 。 示例 3: 输入:prices = [7,6,4,3,1] 输出:0 解释:在这种情况下, 交易无法获得正利润,所以不参与交易可以获得最大利润,最大利润为 0 。

思路

确定dp数组(dp table)以及下标的含义

  • dp[i][0]:第i天持有股票所能获得的最大利润。
  • dp[i][1]:第i天不持有股票所能获得的最大利润。

确定递推公式

  • 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])

dp数组如何初始化

  • dp[0][0] = -prices[0]:第0天买入股票,所以利润为-prices[0]
  • dp[0][1] = 0:第0天不买入也不卖出,利润为0。

确定遍历顺序

  • 从第1天开始遍历,直到最后一天。

举例推导dp数组

  • prices = [7, 1, 5, 3, 6, 4]为例,最终dp[len - 1][1] = 7,即最大总利润为7。

题解

class Solution {
public:
    int maxProfit(vector<int>& prices) {
        int n = prices.size();
        if (n == 0) return 0;
        vector<vector<int>> dp(n, vector<int>(2));
        dp[0][0] = -prices[0];
        dp[0][1] = 0;
        
        for (int i = 1; i < n; ++i) {
            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[n - 1][1];
    }
};