【面試題】連續子數組乘積最大值與柱狀圖中找最大矩形

連續子數組求和最大值比較常見,乘積與求和有相通之處。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的個數。而後再每一行按一維作就能夠了。

相關文章
相關標籤/搜索