算法总结:计算最大利润,允许或不允许【当天同时买卖】的算法逻辑区别

36 阅读2分钟

一:问题出现

在做算法题时,经常刷到计算价格波动的最大利润。在题目中有强调的限制条件,因此思考了关于【允许或不允许当天同时买卖,计算最大利润的逻辑区别】。
如下算法题例子:

捕获.PNG

二:逻辑区别

若不允许当天同时买卖,则需要维护当前的利润状态,可以使用动态规划。

var maxProfit = function (prices) {
    //枚举右,维护左,维护左边最小买入价格
    let maxBenifit = 0
    let minBuyPrice = Infinity
    for (const p of prices) {
        minBuyPrice = Math.min(minBuyPrice, p)
        maxBenifit = Math.max(maxBenifit, p - minBuyPrice)
    }

    return maxBenifit
};

若允许当天同时买卖,则每一天的利润差都可以获取,时间复杂度降低到一维。

// 实际上可以简化为更简单的逻辑
var maxProfit = function (prices) {
    let maxBenifit = 0
    for (let i = 1; i < prices.length; i++) {
        if (prices[i] > prices[i - 1]) {
            // 前一天低点买入,当天高点卖出
            maxBenifit += prices[i] - prices[i-1]
        }
    }
    return maxBenifit
};

三:问题解决与思考

两种不同的条件,核心在于取得最大利润的方法不同,在力扣股票相关的算法题中:

若不允许同一天买卖,则增加了算法题的难度,需要考虑状态转移,大多情况是用动态规划。
若允许,则直接将复杂度降低到贪心策略。

思考1:最大利润结果是否相同?

在两种不同的条件下,取得的最大利润结果是否相同?

答案是:相同的。

为什么?

  1. 任何最优的不允许同一天买卖的交易策略,也是允许同一天买卖的交易策略。
  2. 任何最优的允许同一天买卖的交易策略,都可以转化为等价的不允许同一天买卖的交易策略。(只需要将同一天买卖的操作移除,因为同一天买卖产生的利润为0。)
  3. 从数学上看,最大利润都等于所有上升区间的价格差总和

思考2:需要注意的例外情况

允许同一天买卖,即使用贪心策略,以下结果会与不允许同一天买卖,最大利润的结果不同。

  1. 存在交易手续费。允许同一天买卖会产生更多手续费。
  2. 有交易次数限制。允许同一天买卖会通过当天买卖浪费交易次数。
  3. 有持股数量限制。允许同一天买卖会通过当天买卖调整持股数量。
  4. 价格序列包含盘中波动,非每日单一价格。允许同一天买卖可以利用日内波动赚取更多利润。

四:总结

为了模拟真实市场规则,增加问题难度和思考深度,考虑更复杂的动态规划算法设计,题目中大多数都会不允许同一天买卖。
典型问题: 力扣 121, 122, 123, 188