LeetCode 152. 乘積最大子數組 | Python

152. 乘積最大子數組


題目來源:https://leetcode-cn.com/problems/maximum-product-subarray/

題目


給你一個整數數組 nums ,請你找出數組中乘積最大的連續子數組(該子數組中至少包含一個數字),並返回該子數組所對應的乘積。

示例 1:

輸入: [2,3,-2,4]
輸出: 6
解釋: 子數組 [2,3] 有最大乘積 6。

示例 2:

輸入: [-2,0,-1]
輸出: 0
解釋: 結果不能爲 2, 因爲 [-2,-1] 不是子數組。

解題思路


思路:動態規劃

這道題跟之前【53. 最大子序和】 題有點類似,不過這裏要求的是乘積最大值。

因爲兩道題要求都是連續的,在這裏,我們可以這樣進行狀態設計,也就是以 nums[i] 結尾的連續子數組的最大值。

現在具體看下如何進行狀態設計、推導狀態轉移方程,進而加以實現。

因爲數組中存在着負數,所以有可能導致乘積會從最大變爲最小,同樣的,最小也可能變爲最大。這裏需要注意。

現在,先進行狀態設計:

d[i][j]: 表示以 nums[i] 結尾的連續子數組的最值。在這裏,j 決定計算的是最大值還是最小值。

  • 其中當 j = 0 時,表示計算的是最小值,
  • 當 j = 1 時,表示計算的是最大值。

現在推導狀態轉移方程:

因爲是乘積的關係,nums[i] 數值的正負,與前面的狀態值是有聯繫的,具體如下:

  • 當 nums[i] > 0 時:
    • 與最大值的乘積依然是最大值
    • 與最小值的乘積依然是最小值
  • 當 nums[i] < 0 時:
    • 與最大值的乘積變爲最小值
    • 與最小值的乘積變爲最大值
  • 當 nums[i] = 0 時,這裏無論最大最小值,最終結果都是 0,這裏其實可以合併在上面任意一種情況。

但是還有需要注意的地方,這裏前面的狀態值的正負也是會影響最終的最值。假如,前面的最大值是負數的情況下,也就是 dp[i-1][1] < 0,但這是 nums[i] > 0 的情況下,這裏就要重新考慮,此時的最大值應該是 dp[i][1] = nums[i]。

按照這個思路,將所有情況的狀態轉移方程都寫出來,具體如下:

dp[i][0] = min(nums[i], dp[i-1][0] * nums[i]) if nums[i] >= 0
dp[i][1] = max(nums[i], dp[i-1][1] * nums[i]) if nums[i] >= 0

dp[i][0] = min(nums[i], dp[i-1][1] * nums[i]) if nums[i] < 0
dp[i][1] = max(nums[i], dp[i-1][0] * nums[i]) if nums[i] < 0

具體的代碼實現如下。

代碼實現


class Solution:
    def maxProduct(self, nums: List[int]) -> int:
        if len(nums) == 0:
            return 0
        
        length = len(nums)
        # 初始化
        # dp 數組有兩個元素,一個存儲最大值,一個最小值
        dp = [[0] * 2 for _ in range(length)]
        # 初始化數組首元素爲最大值和最小值
        dp[0][0] = nums[0]
        dp[0][1] = nums[0]
        # 開始遍歷
        for i in range(1, length):
            # 狀態轉移方程
            if nums[i] > 0:
                dp[i][0] = min(nums[i], dp[i-1][0] * nums[i])
                dp[i][1] = max(nums[i], dp[i-1][1] * nums[i])
            else:
                dp[i][0] = min(nums[i], dp[i-1][1] * nums[i])
                dp[i][1] = max(nums[i], dp[i-1][0] * nums[i])

        # 因爲最終要求得最大值,那麼在 dp[i][1] 找得最大即可
        # 初始化返回值
        res = dp[0][1]
        for i in range(1, length):
            res = max(res, dp[i][1])
        return res

實現結果


實現結果


以上就是使用動態規劃,根據題意進行狀態設計,推導出狀態轉移方程,用代碼加以實現,進而解決《152. 乘積最大子數組》問題的主要內容。


歡迎關注微信公衆號《書所集錄》

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