1. 程式人生 > 實用技巧 >LeetCode152. 乘積最大子陣列

LeetCode152. 乘積最大子陣列

要求乘積最大的子陣列(子陣列一定都是連續的),可以暴力列舉子陣列起點和終點,求和。但是肯定超時。

如果用動態規劃,則只需要一遍掃描就可以得出結果。

可以用maxProduct[i]表示以i結尾的最大的子陣列乘積。

如果所有nums[i]都是正數,則maxProduct[i]就是max(nums[i], maxProduct[i - 1] * nums[i]),
也就是當前數和以i - 1結尾的最大子陣列乘積和當前數的乘積的較大值。

但是在這題裡,nums[i]有可能是負數,眾所周知負負得正,所以有可能前面某個子陣列的乘積非常的“負”且當前的nums[i]也是一個負數,
以至於之前的那個負的子陣列的積和nums[i]的乘積反而是最大的。

因此我們不僅需要一個maxProduct陣列記錄以當前位置i結尾的最大子陣列的積,還需要一個minProduct陣列記錄以當前位置i結尾的最小子陣列的積。

對於每一個maxProduct[i],它的值應該是nums[i], maxProduct[i - 1] * nums[i], minProduct[i - 1] * nums[i]三者中最大的,
對於每一個minProduct[i],它的值是三者中最小的。

我們只需要一遍掃描更新所有的maxProduct和minProduct。

最終答案就是maxProduct陣列中的最大值。

程式碼如下:

class Solution {
public:
    int maxProduct(vector<int>& nums) {
        int size = nums.size();
        vector<int> maxProduct(size), minProduct(size);
        maxProduct[0] = nums[0], minProduct[0] = nums[0];
        for(int i = 1; i < size; ++i) {
            maxProduct[i] = max(nums[i], max(maxProduct[i - 1] * nums[i], minProduct[i - 1] * nums[i]));            //這一行和下一行對調位置也行,只要更新了maxProduct和minProduct就好
            minProduct[i] = min(nums[i], min(maxProduct[i - 1] * nums[i], minProduct[i - 1] * nums[i]));
        }
        return *max_element(maxProduct.begin(), maxProduct.end());
    }
};