代码随想录day60
来了老弟
84.柱状图中最大的矩形
思路
本题和42. 接雨水是遥相呼应的两道题目,建议都要仔细做一做,原理上有很多相同的地方,但细节上又有差异,更可以加深对单调栈的理解!42. 接雨水
其实这两道题目先做那一道都可以,但我先写的42.接雨水的题解,所以如果没做过接雨水的话,建议先做一做接雨水,可以参考我的题解:42. 接雨水
此题双指针超时,暂略,后续有空补上~
单调栈
本地单调栈的解法和接雨水的题目是遥相呼应的。
为什么这么说呢,42. 接雨水 是找每个柱子左右两边第一个大于该柱子高度的柱子,而本题是找每个柱子左右两边第一个小于该柱子的柱子。42. 接雨水
这里就涉及到了单调栈很重要的性质,就是单调栈里的顺序,是从小到大还是从大到小。
在题解42. 接雨水中我讲解了接雨水的单调栈从栈头(元素从栈头弹出)到栈底的顺序应该是从小到大的顺序。
那么因为本题是要找每个柱子左右两边第一个小于该柱子的柱子,所以从栈头(元素从栈头弹出)到栈底的顺序应该是从大到小的顺序!
我来举一个例子,如图:
只有栈里从大到小的顺序,才能保证栈顶元素找到左右两边第一个小于栈顶元素的柱子。
所以本题单调栈的顺序正好与接雨水反过来。
此时大家应该可以发现其实就是栈顶和栈顶的下一个元素以及要入栈的三个元素组成了我们要求最大面积的高度和宽度
理解这一点,对单调栈就掌握的比较到位了。
除了栈内元素顺序和接雨水不同,剩下的逻辑就都差不多了,在题解42. 接雨水我已经对单调栈的各个方面做了详细讲解,这里就不赘述了。
剩下就是分析清楚如下三种情况:
- 情况一:当前遍历的元素heights[i]小于栈顶元素heights[st.top()]的情况
- 情况二:当前遍历的元素heights[i]等于栈顶元素heights[st.top()]的情况
- 情况三:当前遍历的元素heights[i]大于栈顶元素heights[st.top()]的情况
Go代码如下:
func largestRectangleArea(heights []int) int {
//单调栈(单调递增)
stack := make([]int, 0)
heights = append([]int{0},heights...)
heights = append(heights,0)
var ans int
stack = append(stack, 0)
for i:=1;i<len(heights);i++{
if heights[i] > heights[stack[len(stack)-1]] {
stack = append(stack, i)
} else if heights[i] == heights[stack[len(stack)-1]] {
stack = stack[:len(stack)-1]
stack = append(stack, i)
} else {
for heights[i] < heights[stack[len(stack)-1]] {
mid := stack[len(stack)-1]
stack = stack[:len(stack)-1]
left := stack[len(stack)-1]
right := i
w := right-left-1
h := heights[mid]
ans = max(ans, w*h)
}
stack = append(stack,i)
}
}
return ans
}
func max(a, b int) int {
if a > b {
return a
}
return b
}