力扣算法学习day41-3
84-柱状图中最大的矩形
题目
代码实现
class Solution {
public int largestRectangleArea(int[] heights) {
// 代码随想录刷题收官之战!速度:21ms
// 首先,比较容易想到双指针思路,就是求每个柱子为中心凹点的最大矩形面积。那么需要从左到右
// 遍历柱子,然后每个柱子还需要遍历找它左边第一个小于它的位置,和右边第一个小于它的位置。
// 双指针很明显时间复杂度是O(n^2),然后感觉用dp优化,很容易想到的就是dp优化双指针需要遍历
// 的时候去找左右第一个小于的值,而这个值可以由dp数组先求得,但是实际操作我发现这个dp数组
// 两个也是需要双重循环的估计速度差不多,就算了。
// 然后速度优化 考虑使用单调栈(单调减,从栈顶到栈底 一次降低)(注:这里栈用于存储坐标)
// 规则:
// 1.如果当前栈顶元素小于或等于当前比较元素,直接压入栈.
// 2.如果当前栈顶元素大于比较元素,弹出栈顶元素,并计算栈顶元素的面积。
// 这里的原理是遇到小于栈顶的元素,那么一定可以确定当前栈顶的左边最小和右边最小的坐标,即
// 这里和双指针计算的原理是一样的,只是因为单调栈的性质确定了左边保存的是比它小的第一个数,
// 而如果遇到的比较的这个数如果比栈顶小,那又确定了它的右边遇到的第一个比它小的元素。
// 这里计算公式是:
// 1.宽为遇到的小于栈顶元素的坐标 - 弹出后存储为mid,栈顶元素的值 - 1; 注:如果弹出后栈为空了,那
// 直接宽 = 1。 然后面积 = 宽 * heights[mid]
// 这里最后还需要处理留在栈中的元素。计算原理同理。
// 这里为了方便计算需要在头尾加上0
int[] height = new int[heights.length+2];
for(int i = 1;i < height.length - 1;i++){
height[i] = heights[i-1];
}
LinkedList<Integer> stack = new LinkedList<>();
int result = 0;
for(int i = 0;i < height.length;i++){
while(!stack.isEmpty() && height[i] < height[stack.peek()]){
int mid = stack.pop();
int x = 0;// 先设置变量x为宽,下面分两种情况赋值
if(stack.isEmpty()){
x = i - mid;
} else{
x = i - stack.peek() - 1;
}
int area = x * height[mid];
if(area > result){
result = area;
}
}
stack.push(i);
}
return result;
// 额,做完了,感觉可能动态规划会更快,明天开始复习,顺便补上dp解法。
}
}