单调栈专题

最近稍微补了一下单调栈的习题(虽然以前做过),加深一下理解。
力扣84 :柱状图中最大的矩形
思路:
首先考虑一下暴力的做法,枚举每根柱子,它能延申的面积 = 左右两边第一个小于他的数组成的宽 * 这个数的值。
在这里插入图片描述
就类似与中间这个黄色的柱子,大于它的都可以延申,直到小于它的就不行,所以这个题目就转化成了枚举每个柱子,并且求每个柱子左右两边第一个小于它的数的位置。
我们可以类似用双指针的写法写一个O(n^2)的做法
代码:

class Solution {
public:
    int largestRectangleArea(vector<int>& heights) {
        int ans = 0;
        vector<int>a;
        a.push_back(0);
        int n = heights.size();
        for(int i = 0; i < heights.size(); i++)
        a.push_back(heights[i]);
        for(int i = 1; i <= n; i++){
            int l = i;
	    	while(l - 1 >= 1 && a[l - 1] >= a[i])l--;
		
	    	int r = i;
		    while(r + 1 <= n && a[r + 1] >= a[i])r++;
		
		    ans = max(ans,a[i] * (r - l + 1));
		    //cout<<a[i] * (r - l + 1)<<endl;
        }
        return ans;
    }
};

这个会超时那么我们考虑一下怎么优化?
单调栈可以用来求左边/右边第一个大于/小于它的数,并且有一个很好的复杂度 O ( n ) O(n) O(n),这是单调栈的应用场景,我们考虑怎么把这个场景带到我们这个题中,我们可以构造一个单调递增的栈,栈里面存的是这个元素对应下标,当 a [ s t a c k [ t o p ] ] < a [ i ] a[stack[top]] < a[i] a[stack[top]]<a[i],说明 s t a c k [ t o p ] stack[top] stack[top]右边第一个小于它的数找到了,并且由于栈是单调递增的,所以左边第一个小于它的数就是 s t a c k [ t o p − 1 ] stack[top - 1] stack[top1],所以我们求一个长度更新答案即可。最后可能栈里面还有元素需要再处理一下。
核心代码:

ans = max(ans,abs(stack[top] - stack[top - 1] + abs(i - stack[top]) - 1) * a[stack[top]]);

代码:

class Solution {
public:
    int h[100000];
    int largestRectangleArea(vector<int>& heights) {
        vector<int>a;a.push_back(-1);
        int n = heights.size();
        for(int i = 0; i < n; i++){
            a.push_back(heights[i]);
        }
        int top = 0;
	    h[++top] = 0;
	    int ans = 0;
	    for(int i = 1; i <= n; i++){
		    while(top != 1&& a[i] < a[h[top]]){
		        ans = max(ans,abs(h[top] - h[top - 1] + abs(i - h[top]) - 1) * a[h[top]]);
		        top--;
		    }
		    h[++top] = i;
	    }
    	while(top != 1){
	        ans = max(ans,(abs(h[top] - h[top - 1]) + n - h[top]) * a[h[top]]);top--;
    	}
	    return ans;
    }
};

总结:个人感觉还是比较难想的,代码实现也有一定的难度。但是单调栈的应用场景是很有限的只有是求左边两边第一个大于/小于当前这个数的位置的题,我们可以考虑单调栈。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值