【題目】**84. 柱狀圖中最大的矩形
給定 n 個非負整數,用來表示柱狀圖中各個柱子的高度。每個柱子彼此相鄰,且寬度爲 1 。
求在該柱狀圖中,能夠勾勒出來的矩形的最大面積。
以上是柱狀圖的示例,其中每個柱子的寬度爲 1,給定的高度爲 [2,1,5,6,2,3]。
圖中陰影部分爲所能勾勒出的最大矩形面積,其面積爲 10 個單位。
示例:
輸入: [2,1,5,6,2,3]
輸出: 10
【解題思路1】暴力法
【解題思路2】單調棧
遍歷到下標4的時候,可以確定高度爲6的寬度最多爲1,然後也可以確定高度爲5的寬度最多爲2,先確定了3位置對應高度的寬度,然後確定2位置對應高度的寬度,符合先進後出的規律
- 入棧一個元素高度,表示這個高度還無法確定其寬度
- 出棧一個元素高度,表示可以確定這個高度的寬度了
- 出棧條件,遍歷到的元素高度嚴格小於當前棧頂元素高度,棧頂元素出棧,順便計算出棧頂元素高度能勾勒出的矩形的寬度和麪積
- 矩形寬度 = 當前遍歷到的下標 - 出棧以後的新棧頂下標 - 1
可以假象最右邊有個高度爲0的柱形其小標爲6,所小標4對應的高度爲2的柱形可以一直擴散到末尾
遇到新棧頂和當前棧頂高度相同的情況,彈出當前的棧頂直接跳過,不計算面積
但也可以不做特殊處理,因爲在計算新棧頂的時候會把不準確的結果替換掉
哨兵1可以省去棧非空判斷
哨兵2可以保證所有元素都出棧(除了哨兵1這個高度爲0的),可以省去遍歷完之後再將棧內剩餘元素出棧的步驟
class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if(len == 0){
return 0;
}
if(len == 1){
return heights[0];
}
int area = 0;
Stack<Integer> stack = new Stack<>();
for(int i = 0; i < len; i++){
//當棧頂元素高度大於當前遍歷到的元素高度
while(!stack.isEmpty() && heights[stack.peek()] > heights[i]){
int height = heights[stack.pop()];
//處理棧頂和新棧頂元素值相同的情況,可以省去這步
while(!stack.isEmpty() && heights[stack.peek()] == height){
stack.pop();
}
int width;
if(stack.isEmpty()){
width = i; //棧空,說明從開頭到當前位置都可以構成高度爲height的矩形
}else{
width = i - stack.peek() - 1;
}
area = Math.max(area, width * height);
}
stack.push(i);
}
//棧中剩餘元素依次出棧,邏輯和上面完全一樣
while(!stack.isEmpty()){
int height = heights[stack.pop()];
//處理棧頂和新棧頂元素值相同的情況,可以省去這步
while(!stack.isEmpty() && heights[stack.peek()] == height){
stack.pop();
}
int width;
//注意這裏直到len都可以構成height高度的矩形,不受下一個heights[i]約束
if(stack.isEmpty()){
width = len;
}else{
width = len - stack.peek() - 1;
}
area = Math.max(area, width * height);
}
return area;
}
}
設置哨兵精簡後的代碼
class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if(len == 0){
return 0;
}
if(len == 1){
return heights[0];
}
int area = 0;
int[] newHeights = new int[len + 2];
for(int i = 0; i < len; i++){
newHeights[i + 1] = heights[i];
}
len += 2;
heights = newHeights; //這樣寫的話,下面的邏輯裏面的數組名就不需要更新了
Stack<Integer> stack = new Stack<>();
stack.push(0);
for(int i = 0; i < len; i++){
//當棧頂元素高度大於當前遍歷到的元素高度
while(heights[stack.peek()] > heights[i]){
int height = heights[stack.pop()];
int width = i - stack.peek() - 1;
area = Math.max(area, width * height);
}
stack.push(i);
}
return area;
}
}