动态规划 - 121. 买卖股票的最佳时机

100 阅读2分钟

4月日新计划更文活动 第27天

前言

动态规划专题,从简到难通关动态规划。

每日一题

今天的题目是 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 <= prices.length <= 105
  • 0 <= prices[i] <= 104

题解

暴⼒

这道题⽬最直观的想法,就是暴⼒,找最优间距了。

function maxProfit(prices: number[]): number {
  let result = 0;
  for (let i = 0; i < prices.length; i++) {
    for (let j = i + 1; j < prices.length; j++) {
      result = Math.max(result, prices[j] - prices[i]);
    }
  }
  return result;
};

image.png

当然直接提交会造成超时

贪心

题目要求查找最大收益,根据贪心思想,只要在每次寻找的过程中记录下最小股价和最大收益,不断更新得到最终结果。具体的处理方法如下:

  1. 从第二天开始遍历股价数组,判断每一天是否是最小的股价,如果是,那么将它记录下来作为当前的买入价。

  2. 每一天都计算以当前股价卖出时的最大收益,并将这个最大收益和之前计算得到的最大收益做比较,如果当前的最大收益比之前的最大收益要大,那么记录下来作为新的最大收益。

  3. 最终返回最大收益。

function maxProfit(prices: number[]): number {
    let minPrice = Infinity;
    let maxProfit = 0;

    for (let i = 0; i < prices.length; i++) {
        if (prices[i] < minPrice) {
            minPrice = prices[i];
        } else if (prices[i] - minPrice > maxProfit) {
            maxProfit = prices[i] - minPrice;
        }
    }

    return maxProfit;
};

image.png

动态规划

  1. 定义 dp 数组

首先我们定义 dp 数组,其中 dp[i] 表示第 i 天卖出股票所能获得的最大利润。在第 i 天卖出股票意味着我们需要在 [0, i-1] 区间内选择一个价格最低的股票进行买入,才能产生最大利润。

  1. 确定递推公式

当我们遍历到第 i 天时,如果要在这一天卖出股票获得最大利润,那么必须在 [0, i-1] 区间内选择一个价格最低的股票进行买入。设这个最低价格为 minPrice,则当前卖出的最大利润为 prices[i] - minPrice。

但是,还需要考虑到,卖出股票获得最大利润是否是在前一天(也就是 i-1)卖出获得的利润更大,还是在当前这一天卖出获得的利润更大。因此我们需要比较两种情况,选择其中的较大值作为 dp[i] 的取值。

所以,得到递推公式:

dp[i] = max(dp[i-1], prices[i]-minPrice)
  1. 初始化dp数组

在本题中,我们可以将 dp[0] 的值赋为 0,即第 0 天不进行任何交易,所以利润为 0。后面的天数都初始化为0,方便后面赋值

  1. 确定遍历顺序

由递推公式可以得到,遍历顺序就是由第0天开始往后直到最后一天

代码:

function maxProfit(prices: number[]): number {
   const n = prices.length;
    if (n < 2) {
        return 0;
    }
    const dp = new Array(n).fill(0);
    let minPrice = prices[0];
    for (let i = 1; i < n; i++) {
        minPrice = Math.min(minPrice, prices[i - 1]);
        dp[i] = Math.max(dp[i - 1], prices[i] - minPrice);
    }
    return dp[n - 1];
};

image.png