【前端er每日算法】动态规划--买卖股票一二

49 阅读4分钟

121. 买卖股票的最佳时机

给定一个数组 prices ,它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。

你只能选择 某一天 买入这只股票,并选择在 未来的某一个不同的日子 卖出该股票。设计一个算法来计算你所能获取的最大利润。

返回你可以从这笔交易中获取的最大利润。如果你不能获取任何利润,返回 0 。

思路

限制:只能买卖一次,这个就是和第二题的区别,所以对于这道题不用动态规划也是可以做出来的,只要求出数组的最大区间就可以了。所以遍历找到最大值和最小值,计算差值就是最后的值。

思路一 求最大差值区间

遍历一次,记录左侧最小值,求差值的最大值

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    let min = Number.MAX_VALUE;
    let result = 0;
    for (let i = 0; i < prices.length; i++) {
        min = Math.min(prices[i], min);
        result = Math.max(prices[i] - min, result);
    }
    return result;
};

思路二:动态规划思路

动态规划最重要的是确定dp数组的含义,以及递推公式。这道题,每天有2种状态,一种是当天持有股票,一个是不持有股票,所以用二维数组表示,数组长度是价格的长度,数组的每一项有2个选项,存储当前持有股票的最大值和不持有股票的最大值。因为是求最大值,所以递推公式需要取max值,而最后的结果取到最后一天为止不持有股票的最大值dp[len - 1][1]

  • 含义:
    • dp[i][0]: 第i天持有股票的最大价值,
    • dp[i][1]: 第i天不持有股票的最大价值
  • 递推公式:
    • dp[i][0] = max(dp[i-1][0], -prices[i]) 前天持有股票,今天不变以及前天不持有股票,今天买入的最大值
    • dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i]), 前天不持有股票,今天依然不持有,以及今天卖出的最大值
  • 初始化:
    • dp[0][0] = -prices[0],
    • dp[0][1] = 0

/**
 * @param {} prices 
 */
var maxProfit = function(prices) {
    const len = prices.length;
    const dp = new Array(len).fill(0).map(item => new Array(2).fill(0));
    dp[0][0] = 0 - prices[0];
    for (let i = 1; i < len; i++) {
        dp[i][0] = Math.max(dp[i - 1][0], 0 - prices[i]);
        dp[i][1] = Math.max(dp[i - 1][1], dp[i - 1][0] + prices[i]);
    }
    return dp[len - 1][1]
}

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

给你一个整数数组 prices ,其中 prices[i] 表示某支股票第 i 天的价格。

在每一天,你可以决定是否购买和/或出售股票。你在任何时候 最多 只能持有 一股 股票。你也可以先购买,然后在 同一天 出售。

返回 你能获得的 最大 利润 。

思路

和上一题的区别是可以多次买卖股票,但是同一时刻只能持有一只股票。

思路1 贪心算法

求这段区间内上升段的所有和,就是只保留上升区间,下降的丢掉,因为会降低。如果把这个区段内想象为间隔为1的区间的所有区间,求最大和,这样求得时候把负数都丢掉,只保留正数就是最大值。

/**
 * @param {number[]} prices
 * @return {number}
 */
var maxProfit = function(prices) {
    let maxProfit = 0;
    for (let i = 1; i < prices.length; i++) {
        if (prices[i] - prices[i - 1] > 0) {
            maxProfit += prices[i] - prices[i - 1];
        }
    }
    return maxProfit;
}

思路2 动态规划

这个就和第一道题一模一样了,基本是通用的公式。

  • 含义:
    • dp[i][0]: 第i天持有股票的最大价值,
    • dp[i][1]: 第i天不持有股票的最大价值
  • 递推公式:
    • dp[i][0] = max(dp[i-1][0], dp[i - 1][1] -prices[i]) 前天持有股票,今天不变以及前天不持有股票,今天买入的最大值,这里是和上一道的唯一区别地方, 多次买卖,那第i-1天不持有股票的价值不一定是0,可能是之前积累的价值,所以将0换为dp[i-1][1]
    • dp[i][1] = max(dp[i-1][1], dp[i-1][0] + prices[i]), 前天不持有股票,今天依然不持有,以及今天卖出的最大值
  • 初始化:
    • dp[0][0] = -prices[0],
    • dp[0][1] = 0
var maxProfit = function(prices) {
    const len = prices.length;
    const dp = new Array(len).fill(0).map(item => new Array(2).fill(0));
    dp[0][0] = 0 - prices[0];
    dp[0][1] = 0;
    for (let i = 1; i < len; 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[len - 1][1];
}

总结

咱就是说动态规划这个到底该怎么想出来,就算第二题的贪心算法也是没想出来的。😔