leetcode - 152. Maximum Product Subarray

算法系列博客之Dynamic Programming

本篇博客將運用動態規劃的思想來解決leetcode上152號問題


問題描述:

Find the contiguous subarray within an array (containing at least one number) which has the largest product.

For example, given the array [2,3,-2,4],
the contiguous subarray [2,3] has the largest product = 6.

找出最大連續子序列乘積的問題主要涉及到連續且可能有非正數,使得問題複雜
如果碰到0,就會發生截斷,前面和後面毫不相干
如果碰到負數更爲複雜,因爲偶數個負數乘積爲正數,也即是說不能截斷

考慮前後依賴關係,嘗試進行線性掃描,假定已掃描到第i個數,max爲當前已掃描得到的最大乘積
就max本身而言,也有正負0三種情況,再考慮根據nums[i]進行分類處理

  • 如果nums[i] 爲正數
          max爲正,則應將nums[i] 累乘到max上
          max爲0,則將max置爲nums[i]
          max爲負,乘上max則恰好得到最小乘積min,此後再次掃描到負數相乘時,又必然得到最大乘積;而當前最大乘積只能在此類似於nums[i]爲0的情況進行截斷
  • 如果nums[i] 爲 0, 則發生截斷,前後毫不相干,記錄max值,並將max置0,最終最大乘積與記錄值比較取最大
  • 如果nums[i] 爲負數
          max爲正,乘上max則恰好得到最小乘積min,此後再次掃描到負數相乘時,又必然得到最大乘積;而當前最大乘積應當不變
          max爲0,則應使max繼續爲 0
          max爲負,則應將nums[i] 累乘到max上

再仔細研究這個過程,發現每次計算max值忽略了之前的最小乘積也可能變成最大乘積
總結起來,每次的最大乘積應該是在max*nums[i], min*nums[i], nums[i]三個數中取最大
同時三個數的計算過程要求我們需要實時更新min,而min恰好也是在這三個數中取最小
過程中記錄max的歷史值,實際上也只需要一個值記錄,然後每次進行更新即可

此時不難寫出實現代碼如下

class Solution(object):
    def maxProduct(self, nums):
        cur_max = nums[0]
        cur_min = nums[0]
        fin_max = cur_max

        for x in nums[1:]:
            max_multi_x = cur_max * x
            min_multi_x = cur_min * x
            cur_max = max(max(max_multi_x, min_multi_x), x)
            cur_min = min(min(max_multi_x, min_multi_x), x)
            fin_max = max(cur_max, fin_max)
        return fin_max

時間複雜度分析,僅需一次遍歷數組,每個遍歷單元只有常數條無嵌套指令,是爲O(n)
空間複雜度分析,整個算法只額外使用了五個整形變量,因而是爲O(1)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章