1. 程式人生 > >LeetCode 152. Maximum Product Subarray (最大乘積子陣列)

LeetCode 152. Maximum Product Subarray (最大乘積子陣列)

Given an integer array nums, find the contiguous subarray within an array (containing at least one number) which has the largest product.

Example 1:

Input: [2,3,-2,4]
Output: 6
Explanation: [2,3] has the largest product 6.

Example 2:

Input: [-2,0,-1]
Output: 0
Explanation: The result cannot be 2, because [-2,-1] is not a subarray.

Reference Answer

思路分析

這個求最大子陣列乘積問題是由最大子陣列之和問題演變而來,但是卻比求最大子陣列之和要複雜,因為在求和的時候,遇到0,不會改變最大值,遇到負數,也只是會減小最大值而已。而在求最大子陣列乘積的問題中,遇到0會使整個乘積為0,而遇到負數,則會使最大乘積變成最小乘積,正因為有負數和0的存在,使問題變得複雜了不少。。

比如,我們現在有一個數組[2, 3, -2, 4],我們可以很容易的找出所有的連續子陣列,[2], [3], [-2], [4], [2, 3], [3, -2], [-2, 4], [2, 3, -2], [3, -2, 4], [2, 3, -2, 4], 然後可以很輕鬆的算出最大的子陣列乘積為6,來自子陣列[2, 3].

那麼我們如何寫程式碼來實現自動找出最大子陣列乘積呢,我最先想到的方比較簡單粗暴,就是找出所有的子陣列,然後算出每一個子陣列的乘積,然後比較找出最大的一個,需要兩個for迴圈,第一個for遍歷整個陣列,第二個for遍歷含有當前數字的子陣列,就是按以下順序找出子陣列: [2], [2, 3], [2, 3, -2], [2, 3, -2, 4], [3], [3, -2], [3, -2, 4], [-2], [-2, 4], [4], 我在本地測試的一些陣列全部通過,於是興高采烈的拿到OJ上測試,結果喪心病狂的OJ用一個有15000個數字的陣列來測試,然後說我程式的執行時間超過了要求值,我一看我的程式碼,果然如此,時間複雜度O(n2), 得想辦法只用一次迴圈搞定。我想來想去想不出好方法,於是到網上搜各位大神的解決方法。其實這道題最直接的方法就是用DP來做,而且要用兩個dp陣列,其中f[i]表示子陣列[0, i]範圍內的最大子陣列乘積,g[i]表示子陣列[0, i]範圍內的最小子陣列乘積,初始化時f[0]和g[0]都初始化為nums[0],其餘都初始化為0。那麼從陣列的第二個數字開始遍歷,那麼此時的最大值和最小值只會在這三個數字之間產生,即f[i-1]*nums[i],g[i-1]*nums[i],和nums[i]。所以我們用三者中的最大值來更新f[i],用最小值來更新g[i],然後用f[i]來更新結果res即可。

Code

class Solution:
    def maxProduct(self, nums):
        """
        :type nums: List[int]
        :rtype: int
        """
        if len(nums) == 1:
            return nums[0]
        res = max_temp = min_temp = nums[0]
        
        for count in nums[1:]:
            pre_max, pre_min = max_temp, min_temp
            max_temp = max(pre_max*count, count, pre_min*count)
            min_temp = min(pre_max*count, count, pre_min*count)
            res = max(res, max_temp)
        return res
                    

C++ Version

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        if (nums.size() == 1){
            return nums[0];
        }
        int res = nums[0], min_temp = nums[0], max_temp = nums[0];
        for (int i=1; i<nums.size(); ++i){
            int pre_max = max_temp;
            int pre_min = min_temp;
            max_temp = max(max(pre_max*nums[i], nums[i]), pre_min*nums[i]);
            min_temp = min(min(pre_max*nums[i], nums[i]), pre_min*nums[i]);
            res = max(max_temp, res);
                
        }
        return res;
    }
};

Note

  • 這種應多複雜情況採用採用多個dp陣列記錄狀態的做法很值得學習,後面很多DP問題都是需要借鑑這種多個dp陣列記錄狀態應對複雜場景約束的動態規劃問題!

參考文獻

[1] http://www.cnblogs.com/grandyang/p/4028713.html