連續子數組求和最大值比較常見,乘積與求和有相通之處。10月9號美團的筆試考到了這題。面試
第一題:原題算法
給一個浮點數序列,求連續子串乘積的最大值,例如 -2.5,4,0,3,0.5,8,-1,則取出的最大乘積連續子串爲3,0.5,8。也就是說,上述數組中,3 0.5 8這3個數的乘積3*0.5*8=12是最大的,並且是連續的。數組
解法一:微信
用動態規劃很好作。問題的關鍵是,序列中有正數也有負數,因此,須要記錄最大值,也要記錄最小值。spa
1 double MaxMul(double *num, int len) 2 { 3 if(num == NULL || len < 1) 4 return 0; 5 6 double *maxMul = new double[len]; 7 double *minMul = new double[len]; 8 maxMul[0] = num[0]; 9 minMul[0] = num[0]; 10 double maxM = num[0]; 11 for(int i = 1; i < len; ++i) 12 { 13 maxMul[i] = maxMul[i-1]*num[i] > num[i] ? maxMul[i-1]*num[i] : num[i]; 14 maxMul[i] = maxMul[i] > minMul[i-1]*num[i] ? maxMul[i] : minMul[i-1]*num[i]; 15 minMul[i] = minMul[i-1]*num[i] < num[i] ? minMul[i-1]*num[i] : num[i]; 16 minMul[i] = minMul[i] < maxMul[i-1]*num[i] ? minMul[i] : maxMul[i-1]*num[i]; 17 maxM = maxM > maxMul[i] ? maxM : maxMul[i]; 18 } 19 delete[] maxMul; 20 delete[] minMul; 21 return maxM; 22 }
解法二:設計
也能夠掃一遍序列作出來,不過也要記錄最大值和最小值,以及當前的最大值和最小值,噹噹前的最大值小於1的時候,設置爲當前的序列值,呃,感受語言有點繞,+_+,能夠看《劍指offer》面試題31:連續子數組的最大和,類比一下就好了。仍是用代碼說話吧,邏輯會比較清楚。code
1 double MaxMul2(double *num, int len) 2 { 3 if(num == NULL || len < 1) 4 return 0; 5 6 double maxM = num[0]; 7 double maxMul = num[0]; 8 double minMul = num[0]; 9 double maxCur = num[0]; 10 double minCur = num[0]; 11 for(int i = 1; i < len; ++i) 12 { 13 if(maxCur < 1) 14 maxCur = num[i]; 15 else 16 maxCur *= num[i]; 17 minCur *= num[i]; 18 if(maxCur < minCur) 19 { 20 double tmp = maxCur; 21 maxCur = minCur; 22 minCur = tmp; 23 } 24 maxMul = maxMul > maxCur ? maxMul : maxCur; 25 minMul = minMul < minCur ? minMul : minCur; 26 } 27 return maxMul; 28 }
兩個解法的時間複雜度都是O(1),解法一的空間複雜度是O(n),解法二的空間複雜度也是O(1)。其實解法一的空間複雜度也能夠降爲O(1),不用數組,用四個變量便可。blog
第二題:原題數學
在柱狀圖中找最大的矩形:給一組非負的整數來表示一個柱狀圖,設計一個算法找到最大面積的能適合到柱狀圖內的矩形。好比,對於這組數,1 2 3 4 1 ,有兩種可能的方案,一種是適合到 2 3 4 內的矩形,面積是 2*3;另外一種是適合到 3 4 內的矩形,面積是 3*2。table
用數學點的描述就是,找所給數組的一個連續子數組,使該子數組的最小值與數組長度乘積最大。
解法是在待字閨中微信公衆帳號裏面看到的,一個線性算法是用堆棧來保存當前可能的矩形(高度和起始位置)。從左到右掃描,對一個元素,若是
a)大於棧頂元素, push;
b)小於的話,pop全部的大於它的元素,計算面積,更新最大值。這時若是堆棧空,push一個新的元素,高度等於當前元素,起始位置爲0;不然,push當前元素高度和棧頂的起始位置。
好比1 3 2 2 3這個數組,操做以下:
i |
C[i] |
棧操做 |
最大值 |
棧內容 |
0 |
1 |
push (1,0) |
(1,0) |
|
1 |
3 |
push (3,1) |
(3,1)(1,0) |
|
2 |
2 |
pop (3,1),push (2,1) |
(2-1)*3=3 |
(2,1)(1,0) |
3 |
2 |
什麼都不作 |
(2,1)(1,0) |
|
4 |
3 |
push(3,4) |
(3,4)(2,1)(1,0) |
|
5 |
0 |
pop(3,4) |
(5-4)*3=3 |
(2,1)(1,0) |
5 |
0 |
pop(2,1) |
(5-1)*2=8 |
(1,0) |
5 |
0 |
pop(1,0) |
(5-0)*1=5 |
代碼以下:
1 int MaxArea(int *num, int len) 2 { 3 if(num == NULL || len < 1) 4 return 0; 5 6 stack<int> numStack; 7 stack<int> indStack; 8 numStack.push(num[0]); 9 indStack.push(0); 10 int lastPopInd = 0; 11 int maxMul = num[0]; 12 for(int i = 1; i < len; ++i) 13 { 14 if(num[i] > numStack.top()) 15 { 16 numStack.push(num[i]); 17 indStack.push(i); 18 } 19 else if(num[i] < numStack.top()) 20 { 21 while(!numStack.empty() && num[i] < numStack.top()) 22 { 23 int numPop = numStack.top(); 24 lastPopInd = indStack.top(); 25 maxMul = (numPop * (i - lastPopInd)) > maxMul ? (numPop * (i - lastPopInd)) : maxMul; 26 numStack.pop(); 27 indStack.pop(); 28 } 29 if(numStack.empty() || num[i] > numStack.top()) 30 { 31 numStack.push(num[i]); 32 indStack.push(lastPopInd); 33 } 34 } 35 } 36 while(!numStack.empty()) 37 { 38 int numPop = numStack.top(); 39 lastPopInd = indStack.top(); 40 maxMul = (numPop * (len - lastPopInd)) > maxMul ? (numPop * (len - lastPopInd)) : maxMul; 41 numStack.pop(); 42 indStack.pop(); 43 } 44 return maxMul; 45 }
擴展問題是:
在一個位圖中找面積最大的白色矩形:給你一個NxN的黑白位圖,找一個面積最大的全白色的矩形。注意了,是一個矩形,不是任意一個白色相連的區域。
能夠生成一個新的矩陣C,C[i][j]表示第j列,從第i個元素開始,包括第i個元素,向上數,直到遇到0時,1的個數。而後再每一行按一維作就能夠了。