leetcode 84 Largest Rectangle in Histogram (單調棧)
上題目
題目大意為:給一個數組代表一個柱狀圖,陣列中每一個元素依次代表柱狀圖中每個“柱”的高,求這個柱狀圖能包含的最大矩形面積。
思考:最終矩形的高一定等於某個“柱”的高,寬為這個“柱”左右能延伸到的最大距離之和(直到遇見某個“柱”的高低於當前高)。暴力就是對於每一個“柱”,向左和向右延伸到極限得出寬,再乘以高,複雜度是n的平方。
可以用單調棧(棧中的元素單調遞增)對這個過程進行簡化,棧中每個元素包含兩個屬性,一是“柱”高(設為x),二是以這個柱高向左能延伸到的最遠距離(設為y,y包括柱本身的寬度1,故y初值為1),由棧底到棧頂每個元素的柱高x依次遞增,棧頂元素柱高x最大。
整個演算法由不斷的入棧和出棧構成,將給定的陣列元素依次入棧,入棧時計算當前元素向左能延伸到的最遠距離,定義後面要用到的累加寬度w = 0,入棧時有兩種可能:
(1)棧頂元素柱高大於當前元素柱高,出棧(保證棧的單調性,且此時可以計算面積,後面再說)。累加出棧元素的寬度(這個累加寬度代表的是:新的棧頂元素可以向右延伸這個寬度,這也是用遞增棧的原因,由於出棧元素高於新的棧頂元素,那麼出棧元素向左能延伸到的最遠處,新的棧頂元素至少也能向右延伸到),若棧不空且出棧後新的棧頂元素柱高仍高於當前元素,繼續(1)
(2) 棧頂元素柱高小於當前元素柱高,此時當前元素直接入棧,當前元素的y = 1+w,w代表當前元素之前所有高於當前元素的元素寬度之和,即當前元素可以向左延伸至1+w
出棧時,出棧元素向右能延伸的距離為當前w,故面積為(w+y)*x,計算並更新最大面積。
例如對於題中[2,1,5,6,3,2],以(x,y)表示棧中元素,max代表最大面積
(2,1)準備進棧,初始化w = 0,發現棧空,進棧
(1,1)準備進棧,初始化w = 0,發現其柱高小於棧頂元素,(2,1)出棧,計算面積得 2*1 = 2,max = 2
累加寬度w = w + 1 = 1,y = 1+w = 2,(1,2)進棧
(5,1)準備進棧,初始化w = 0,發現棧頂元素柱高小於當前元素,進棧
(6,1)進棧,同上,此時棧中元素為(1,2)(5,1)(6,1)
(2,1)準備進棧,初始化w = 0,發現其柱高小於棧頂元素,(6,1)出棧,計算面積得 6*1 = 2,max = 6
累加寬度w = w + 1 = 1,接著(5,1)出棧,計算面積得(1 + 1)*5 = 10,max = 10,累加寬度w = w + 1 = 2,出棧完畢。y = 1 + w = 3,(2,3)進棧,此時棧中元素為(1,2)(2,3)
(3,1)進棧,此時棧中元素為(1,2)(2,3)(3,1)
將棧中剩餘元素依次出棧:
初始化w = 0,(3,1)出棧,計算面積得 3*1 = 8,max不變,累加寬度w = w + 1 = 1,接著(2,3)出棧,計算面積得(1+3)*2 = 8,max不變,累加寬度w = w + 3 = 4,接著(1,2)出棧,計算面積得(4+2)*1 = 6,面積不變,出棧完畢。
最終max = 10
上AC程式碼:
class Solution {
private static class Node{
public int height;
public int weight;
public Node(int height, int weight) {
this.height = height;
this.weight = weight;
}
}
public int largestRectangleArea(int[] heights) {
if(heights==null||heights.length==0)
return 0;
int max = 0;
Stack<Node> stack = new Stack<>();
int index = 0;
stack.push(new Node(heights[index++],1));
Node temp;
int areaSize ,count;
for(;index<heights.length;index++) {
count = 0;
while (!stack.empty() && stack.peek().height >= heights[index]) {
temp = stack.pop();
count += temp.weight;
areaSize = temp.height*count;
max = max > areaSize ? max : areaSize;
}
stack.push(new Node(heights[index],count+1));
}
count = 0;
while (!stack.empty()){
temp = stack.pop();
count += temp.weight;
areaSize = temp.height*count;
max = max > areaSize ? max : areaSize;
}
return max;
}
}
PS:開始在POJ 2559 (題目一樣)上提交,怎麼改都是wrong answer,後來只好去leetcode,發現是函式的最開始沒有判斷陣列是否為空 orz,以後一定記得判斷!!!