JS动态规划-求买卖股票的最佳时机

207 阅读2分钟

今天南京下雨了,雨天的巷子特别有感觉

正题

给定一个数组 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。

  乍一看题目还是比较简单的,无非就是求得数组中最大的差是多少,限制条件就是最小值要在最大值的左边。因为天数是不可能倒着过的。第一直觉就是做暴力破解,循环遍历这个数组,找到每一个元素右侧对应能买卖股票的最佳时机。

image.png

如上图所示:

7 能对应的最大售出值不存在

1 能对应的最大售出值是6

5 能对应的最大售出值是6

3 能对应的最大售出值是6

6 能对应的最大售出值不存在

4 能对应的最大售出值不存在

所以可以得出方法一: 暴力枚举法

var maxProfit = function(prices) {
    let res = 0
    for(let index = 0 ; index < prices.length - 1; index++) {
        const n1 = prices[index]
        let max = prices[index + 1]
        for (let j = index + 1 ; j < prices.length; j++) {
            max  = max > prices[j]  ? max : prices[j]
        }
        res = res > max - n1 ? res : max - n1
    }
    return res
};

但是以上这个方法可以说是对性能毫无要求,我们可以用一个非常大的数组作为测试用例。

image.png 可以看到他的用是时间已经超过了5秒多,这在实际运用中可以说是效率极低的。那么能不能讲结果控制在毫秒级呢?

方法二: 动态规划法

动态规划的核心是每实现一步都会有状态的改变,从而判断下一步操作。那么我们可以给定一个数组dpList,记录原数组对应下标的数的最大利润。

ScreenRecorderProject11.gif

var maxProfit = function(prices) { 
   let dpList = new Array(prices.length).fill(0)
   let min = prices[0]
  for (let i = 1 ; i < prices.length ; i++) {
      if (prices[i] > min) {
          dpList[i] = prices[i] - min
      } else {
          dpList[i] = 0
          min = prices[i]
      }
  }
  return Math.max(...dpList)
}

image.png

同样的测试用例,仅仅只用了80ms,远比暴力枚举效率要高出很多。