題目
給你一個整數數組 nums ,請你找出數組中乘積最大的連續子數組(該子數組中至少包含一個數字),並返回該子數組所對應的乘積。
示例 1:
輸入: [2,3,-2,4] 輸出: 6 解釋: 子數組 [2,3] 有最大乘積 6。 示例 2:
輸入: [-2,0,-1] 輸出: 0 解釋: 結果不能爲 2, 因爲 [-2,-1] 不是子數組。
來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/maximum-product-subarray
著作權歸領釦網絡所有。商業轉載請聯繫官方授權,非商業轉載請註明出處。
分析
這題是我們最近《算法分析與設計》這門課的一道例題。採用動態規劃的方法就可以在O(n)的時間複雜度內解決。由於這裏不需要提供返回結果的起始和終止位置,因此連數組都可以退化成只保存max和min。
Q:爲什麼這裏需要保存一個min的數組呢?
A:因爲題目中給出的條件只有整數數組,如果是非負整數就可以只用保存最大值了。這裏的“最小值”其實是“負絕對值”的數中的絕對值最大值,當乘上一個負數以後,這個數很有可能變成絕對值最大的正數。
既然明確了動態規劃算法,那就說一下遞推式:
int a = max*nums[i],b = min*nums[i];
max = MAX(MAX(nums[i],a),b);
min = MIN(MIN(nums[i],a),b);
top = MAX(top, max);
這裏其實max
和min
就是max*nums[i]
、 min*nums[i]
和nums[i]
中的最大值和最小值。可以分類討論證明這個遞推式的正確性。top
用於記錄max
的最大值,當作最終結果返回top
。
代碼
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
int maxProduct(int* nums, int numsSize){
long i,top = nums[0], max=nums[0], min=nums[0], temp;
for (i = 1; i < numsSize; i++){
int a = max*nums[i],b = min*nums[i];
max = MAX(MAX(nums[i],a),b);
min = MIN(MIN(nums[i],a),b);
top = MAX(top, max);
}
return top;
}
運行結果
結果已經不錯了。
在評論區找到一個思路類似的小夥伴,我在寫的時候也參考了他的代碼。這裏附上他的代碼:
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
int maxProduct(int* nums, int numsSize){
long i,realmax = nums[0], max=nums[0], min=nums[0], temp;
for (i = 1; i < numsSize; i++){
if(nums[i] < 0) {
temp = max;
max = min;
min = temp;
}
max = MAX(max*nums[i], nums[i]);
min = MIN(min*nums[i], nums[i]);
realmax = MAX(realmax, max);
}
return realmax;
}
作者:chenpuo
鏈接:https://leetcode-cn.com/problems/maximum-product-subarray/solution/152-cheng-ji-zui-da-zi-shu-zu-shu-xue-si-xiang-max/
來源:力扣(LeetCode)
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
運行結果和我的差不多。不過他通過對nums[i]符號的判斷以及轉換,節約了部分空間和時間開銷,max和min的調用次數也會比我寫的稍好一點。
感謝大家的支持和點贊。