Add Date 2014-09-23算法
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
.spa
簡單來講就是在一個 int 數組中找一段連續的子數組,使其乘積最大,數組中包含正數、負數和0。不考慮乘積太大超出範圍。code
解法一:blog
動態規劃的方法,今天在微信「待字閨中」中看到的,借來分享。遍歷一遍,優於解法二,複雜度O(n).遞歸
1 int max2(int a, int b) { 2 if(a > b) return a; 3 return b; 4 } 5 6 int max3(int a, int b, int c) { 7 return max2(max2(a, b), c); 8 } 9 10 int min2(int a, int b) { 11 if(a > b) return b; 12 return a; 13 } 14 15 int min3(int a, int b, int c) { 16 return min2(min2(a, b), c); 17 } 18 19 int maxProduct(int A[], int n) { 20 int max = A[0]; 21 int min = A[0]; 22 int a = max; 23 for(int i = 1; i < n; ++i) { 24 int tmpMax = max * A[i]; 25 int tmpMin = min * A[i]; 26 max = max3(tmpMax, tmpMin, A[i]); 27 min = min3(tmpMax, tmpMin, A[i]); 28 a = max2(max, a); 29 } 30 return a; 31 }
解法二:leetcode
以前作過找連續子數組使其加和最大,比較簡單,見《劍指offer》Q31。get
剛開始也試圖從那道題中找思路,發現不太科學…後來本身摸索出一個思路,分享一下。it
首先,任何一個數字和0相乘獲得的都是0;另外,不考慮0的狀況下,由於數字都是整數,因此乘積的絕對值是不會變小的;再次,負負得正。
基於這三點考慮,首先基於遞歸的思想用0分段,也就是說,把數組 A 拆分爲 [一段不包含0的數組]、[0]、[剩下的數組],並設 rel1 爲不包含0的子數組獲得的最大乘積,rel2 爲剩下的數組獲得的最大乘積,那麼,數組 A 的最大乘積就是 max{rel1,0,rel2}。rel2遞歸的用這個思路獲得。
而後,就是求一個不包含0的數組的最大乘積。因爲負負得正,能夠想到,若是負數的個數爲偶數,那麼全部的數字相乘就是那個最大乘積;若是負數的個數爲奇數,那麼必定是某一個負數的左邊全部數字乘積或者右邊全部數字乘積爲最大,因此就能夠從前向後遍歷數組,並把全部元素相乘,用 numAll1 記錄這個乘積,同時每次更新 num1 爲從前到後相乘過程當中最大的乘積;而後再從後向前遍歷數組,用 numAll2 記錄乘積,num2 記錄最大值,這樣整個數組的最大乘積就是 max{num1,num2}。
若是你以爲不理解爲何最大乘積的子數組必定是從第一個數字連續的一個子數組,或者是從最後一個數字連續的子數組,能夠這樣想:
若是這個乘積最大的子數組是中間的某一段,固然排除掉只有一個元素且爲負數的狀況,那麼這個乘積必定是正數(這個還不懂的話本身想一下吧,簡單的),若是
1.這段子數組左邊(右邊)是全正的,那麼和左邊(右邊)全部的數相乘的結果必定不會比當前的結果小,因此能夠從左邊(右邊)連續;因此這段子數組左邊和右邊必定都有負數!
2.這段子數組左邊(右邊)有偶數個負數,同1是不可能的;並且若是有多個負數,必定能夠有偶數個能夠包含在中間這段子數組中使乘積更大;因此必定左邊和右邊各有一個負數!
3.若是左邊和右邊各有一個負數,那麼就有兩個負數,這樣的話把整個數組相乘的結果必定不小於中間這段子數組。
這個算法中遍歷整個數組三次,複雜度爲O(n).
終於把邏輯說完了,我的以爲很囉嗦,只是想說明白點,不知道你們有沒明白,下面附 code,歡迎其它思路。
1 class Solution { 2 public: 3 int maxProductNo0(int A[], int n) { //沒有0的數組求最大乘積 4 int num1 = A[0]; 5 int numAll1 = A[0]; 6 for(int i = 1; i < n; ++i) { 7 numAll1 *= A[i]; 8 num1 = numAll1 > num1 ? numAll1 : num1; 9 } 10 11 int num2 = A[n-1]; 12 int numAll2 = A[n-1]; 13 for(int i = n-2; i >= 0; --i) { 14 numAll2 *= A[i]; 15 num2 = numAll2 > num2 ? numAll2 : num2; 16 } 17 return num1 > num2 ? num1 : num2; 18 } 19 20 int maxProduct(int A[], int n) { //求數組最大乘積 21 if(A == NULL || n < 1) 22 return 0; 23 int index0 = 0; 24 int rel1 = A[0]; 25 int rel2 = A[0]; 26 bool have0 = false; 27 for(; index0 < n; ++index0) { 28 if(A[index0] == 0) { 29 have0 = true; 30 break; 31 } 32 } 33 if(index0 > 0) 34 rel1 = maxProductNo0(A, index0); //沒有0的數組的最大乘積 35 if(n-index0-1 > 0) 36 rel2 = maxProduct(A+index0+1, n-index0-1); //剩下的數組的最大乘積 37 rel1 = rel1 > rel2 ? rel1 : rel2; 38 if(have0) 39 rel1 = rel1 > 0 ? rel1 : 0; 40 return rel1; 41 } 42 };