算法系列博客之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)