题目描述
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。
求在该柱状图中,能够勾勒出来的矩形的最大面积。
以上是柱状图的示例,其中每个柱子的宽度为 1,给定的高度为 [2,1,5,6,2,3]。
图中阴影部分为所能勾勒出的最大矩形面积,其面积为 10 个单位。
示例:
输入: [2,1,5,6,2,3]
输出: 10
暴力算法 (超时)
复杂度分析:
时间复杂度:O(N^2) 这里 NN 是输入数组的长度。
空间复杂度:O(1)。
算每个正方形的横竖的最大面积
public class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if(len == 0) return 0;
int res = 0;
for(int i = 0; i < len; i++){
int curHeight = heights[i];
int left = i;
int right = i;
while(left >0 && heights[left - 1] >= curHeight){
left--;
}
while(right < len-1 && heights[right + 1] >= curHeight){
right++;
}
int width = right - left + 1;
int area = width * curHeight;
res = Math.max(res, area);
}
return res;
}
}
单调栈
复杂度分析:
时间复杂度:O(N),输入数组里的每一个元素入栈一次,出栈一次。
空间复杂度:O(N),栈的空间最多为 N。
import java.util.*;
public class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if (len == 0) return 0;
if (len == 1) return heights[0];
//单调栈的思路就是用栈实现单调递增
//有比要放进去的大的 就弹出来 弹到没有比要放进去的大了 就把要放进去的放进去
int res = 0;
Deque<Integer> stack = new ArrayDeque<>(len);
for (int i = 0; i < len; i++) {
// 这个 while 很关键,因为有可能不止一个柱形的最大宽度可以被计算出来
while (!stack.isEmpty() && heights[i] < heights[stack.peekLast()]) {
int curHeight = heights[stack.pollLast()];
while (!stack.isEmpty() && heights[stack.peekLast()] == curHeight) {
stack.pollLast();
}
int curWidth;
if (stack.isEmpty()) {
//柱子的宽度 (栈为空 就是第一个放进去的时候)
curWidth = i;
} else {
//现在柱子的宽度 = 挨着这根柱子的比它大的柱子 i - (最大数的位子) - 第i根柱子 中间的就是可以组成正方形的
curWidth = i - stack.peekLast() - 1;
}
// System.out.println(curHeight+ " " +curWidth);
res = Math.max(res, curHeight * curWidth);
}
stack.addLast(i);
}
//来计算剩下的在栈内的 按柱高从大到小来找柱子面积
while (!stack.isEmpty()) {
int curHeight = heights[stack.pollLast()];
while (!stack.isEmpty() && heights[stack.peekLast()] == curHeight) {
stack.pollLast();
}
int curWidth;
if (stack.isEmpty()) {
//最低的肯定是所有都能满足 所以宽是len
curWidth = len;
} else {
//宽度 = 长度 - 下一个大的柱子的位置
curWidth = len - stack.peekLast() - 1;
}
// System.out.println(curHeight+ " " +curWidth);
res = Math.max(res, curHeight * curWidth);
}
return res;
}
}
*****单调栈 + 哨兵
复杂度分析:
时间复杂度:O(N),输入数组里的每一个元素入栈一次,出栈一次。
空间复杂度:O(N),栈的空间最多为 N。
import java.util.ArrayDeque;
import java.util.Deque;
public class Solution {
public int largestRectangleArea(int[] heights) {
int len = heights.length;
if (len == 0) {
return 0;
}
if (len == 1) {
return heights[0];
}
int res = 0;
int[] newHeights = new int[len + 2];
newHeights[0] = 0;
System.arraycopy(heights, 0, newHeights, 1, len);
newHeights[len + 1] = 0;
len += 2;
heights = newHeights;
Deque<Integer> stack = new ArrayDeque<>(len);
// 先放入哨兵,在循环里就不用做非空判断
stack.addLast(0);
for (int i = 1; i < len; i++) {
while (heights[i] < heights[stack.peekLast()]) {
int curHeight = heights[stack.pollLast()];
int curWidth = i - stack.peekLast() - 1;
res = Math.max(res, curHeight * curWidth);
}
stack.addLast(i);
}
return res;
}
}
单调栈题目
- 接雨水(困难) 暴力解法、优化、双指针、单调栈
- 每日温度(中等) 暴力解法 + 单调栈
- 下一个更大元素 I(简单) 暴力解法、单调栈
- 去除重复字母(困难) 栈 + 哨兵技巧(Java、C++、Python)
- 股票价格跨度(中等) 「力扣」第 901 题:股票价格跨度(单调栈)
- 移掉K位数字
- 最短无序连续子数组