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

63 阅读2分钟

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

前言

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

每日一题

今天的题目是 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 。

提示:

  • 1 <= prices.length <= 3 * 104
  • 0 <= prices[i] <= 104

题解

动态规划

  1. 定义dp数组以及下标含义
  • dp[i][0] 表示第i天卖出股票所能获得的最大利润

  • dp[i][1] 表示第i天买入股票所能获得的最大利润

  1. 推导递推公式

考虑第i天可以进行的两项操作:卖出股票或买入股票。如果要卖出股票,则在前i-1天中必须至少进行一次买入操作。因此,在第i天可以获得的最大利润分为两种情况:

  1. 未持有股票:如果在前i-1天中已经卖出了股票,那么第i天不进行任何操作;否则,如果在前i-1天中持有了股票,那么在第i天进行卖出操作,获得的利润是dp[i-1][1]+prices[i]
  2. 持有股票:如果在前i-1天中已经持有了股票,那么第i天不进行任何操作;否则,在第i天进行买入操作,获得的利润是 dp[i-1][0]-prices[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])
  1. 初始化dp数组

定义一个二维数组dp

初始值需要考虑边界情况。在本问题中可以确定的是,如果只有1天,那么不进行任何交易,收益为0。因此,当数组prices长度为1时,我们直接返回0即可。

于其他情况,我们需要初始化dp数组。当第1天买进股票时,所需要的成本就是prices[0],因此我们可以初始化dp[0][1] = -prices[0]。当第1天卖出股票时,由于此时尚未拥有任何股票,因此利润也为0,我们可以初始化dp[0][0] = 0。根据dp数组的定义,在其他情况下,我们可以将二维数组dp所有元素初始化为0,代码实现如下:

let dp = Array.from(new Array(2), () => new Array(2).fill(0));
dp[0][0] = 0;
dp[0][1] = -prices[0];
  1. 确定遍历顺序

由递推公式可得,按照顺序遍历数组prices中的所有元素

代码

function maxProfit(prices: number[]): number {
    let len = prices.length;
    if (len <= 1) return 0;
    let dp = Array.from(new Array(2), () => new Array(2).fill(0));
    dp[0][1] = -prices[0];
    dp[1][0] = 0;
    dp[1][1] = Number.NEGATIVE_INFINITY;
    for (let i = 1; i < len; i++) {
        dp[i % 2][0] = Math.max(dp[(i - 1) % 2][0], dp[(i - 1) % 2][1] + prices[i]);
        dp[i % 2][1] = Math.max(dp[(i - 1) % 2][1], dp[(i - 1) % 2][0] - prices[i]);
    }
    return dp[(len - 1) % 2][0];
};

image.png