【力扣刷题】单调栈总结

单调栈理论

1.定义

从栈底元素到栈顶元素呈单调递增或单调递减,栈内序列满足单调性的栈

2.性质

(1)当新元素在单调性上优于栈顶时(单增栈新元素比栈顶大,单减栈新元素比栈顶小),压栈,栈深+1;
(2)当新元素在单调性与栈顶相同(新元素于栈顶相同)或劣于栈顶时(单增栈新元素比栈顶小,单减栈新元素比栈顶大),弹栈,栈深-1;

3.适用场景

在一个数组arr[N]中,给定一个数num,分别求解各arr[i]左边比num大的距离其最近的和右边比num大的距离其最近的数,使得其时间复杂度为O(N)(优于暴力解法的O(n*n))。

4.经典例题及模型

单调栈模板代码

1.使用数组进行模拟单调递增栈:
cin>>nums[i]
int s[maxn],tot=0;
for(int i=0;i<maxn;i++){
	while(tot>=1&&s[tot-1]>=nums[i]){
	    tot--;
	}
	if(tot) cout<<stac[tot-1]<<' ';
    else cout<<-1<<' ';
	s[tot++]=nums[i];
}
2.使用栈进行模拟单调递增栈:
cin>>nums[i]
stack<int> s;
for(int i=0;i<n;i++){
        while(!s.empty()&&s.top()>=nums[i]){
            s.pop();
        }
        if(!s.empty()) cout<<s.top()<<' ';
        else cout<<-1<<' ';
        s.push(nums[i]);
}
   
在这里插入代码片
实际的应用:
1.利用单调递增栈进行左右搜索高度大于或等于自身的最长区间

**题目:**力扣 84. 柱状图中最大的矩形
给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。求在该柱状图中,能够勾勒出来的矩形的最大面积。

示例:
输入: [2,1,5,6,2,3]
输出: 10

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/largest-rectangle-in-histogram
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

如图是一系列的离散的数列,若一A点为高求最大的矩形,需找到左与右第一个比它小的数据点,以二者距离为宽乘以高可得面积,暴力解法很容易就可以得出,但时间复杂度为n^2。为提高算法效率,引入单调递增栈的数据结构,其特性为栈内的元素以出栈方向严格单调递增,利用这一特性可以很好的在栈顶为A点入栈新点B不用出栈时(A点的压栈方向的下一个元素为点C),快速的确定A点左与右第一个比它小的数据点分别为点C与点A,此时算法复杂度为构造单调栈的时间复杂度n,大大提升了算法效率。
【力扣刷题】单调栈总结_第1张图片
具体代码如下:

class Solution {
public://使用单调栈的思想
    int largestRectangleArea(vector<int>& heights) {
        stack<int> s;
        int retmax=0;
        int len=heights.size(); //递增单调栈  (L,R)开区间
        for(int i=0;i<len;i++){  //将出栈的元素作为高计算,L为该元素的栈下元素,R为将要入栈的元素;
            while(!s.empty()&&heights[s.top()]>=heights[i]){
                int  h=s.top();
                s.pop();
                int l;
                if(s.empty()) l=-1;
                else l=s.top();
                retmax=max(retmax,(i-l-1)*heights[h]);
            }
            s.push(i);
        }
        while(!s.empty()){//将栈内的元素作为高计算,L为该元素的栈下元素,R为数组长度;
            int  h=s.top();
            s.pop();
            int l;
            if(s.empty()) l=-1;
            else l=s.top();
            retmax=max(retmax,(len-l-1)*heights[h]);
        }
        return retmax;  //此时全部元素分为二部分计算完毕
    }
};
2.第一题的进阶版(增加了一维)

题目: 85. 最大矩形
给定一个仅包含 0 和 1 、大小为 rows x cols 的二维二进制矩阵,找出只包含 1 的最大矩形,并返回其面积。
【力扣刷题】单调栈总结_第2张图片

示例:
输入:matrix = [[“1”,“0”,“1”,“0”,“0”],[“1”,“0”,“1”,“1”,“1”],[“1”,“1”,“1”,“1”,“1”],[“1”,“0”,“0”,“1”,“0”]]
输出:6
解释:最大矩形如上图所示。

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximal-rectangle
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路:

由第一题可以启发到,该题是在找一个最大矩阵,最大矩阵由高和宽组成,与第一题类似,但增加了多行,以示例为例,以第一行底构建矩阵的高度数组为10100,第二行为20211,第三行为31322,第四行为30030;题目要求寻找最大,那么简单的方法是遍历所有可能的矩形比较得最大,那么组合的方法为底与高的组合,底可以是每一行,底确定了那么高也就很好确定,采用题目一的方法分别对以四行为底的矩阵进行更新最大矩阵。时间复杂度为y*x.
具体代码如下:

class Solution {
public:
    int fun(vector<int> nums){   //根据高度矩阵,计算最大矩形,方法是引入单调栈,更新nums[i]为高的最大矩阵
        int len=nums.size();
        stack<int> s;
        int ret=0;
        for(int i=0;i<len;i++){
            while(!s.empty()&&nums[s.top()]>=nums[i]){
                int r=i;
                int h=s.top();
                s.pop();
                int l=s.empty()?-1:s.top();
                ret=max(ret,(r-l-1)*nums[h]);
            }
            s.push(i);
        }
        while(!s.empty()){
            int r=len;
            int h=s.top();
            s.pop();
            int l=s.empty()?-1:s.top();
            ret=max(ret,(r-l-1)*nums[h]); 
        }
        return ret;
    }
    int maximalRectangle(vector<vector<char>>& matrix) {
        int y=matrix.size();
        if(y==0) return 0;
        int x=matrix[0].size();
        vector<int> num(x,0);
        int retmax=0;
        for(int i=0;i<y;i++){     //依次换行作为矩形的底
            for(int j=0;j<x;j++){  //更新高度数组信息
                if(matrix[i][j]=='0') num[j]=0;
                else num[j]++;
            }
            retmax=max(retmax,fun(num));//更新最大值结果
        }
        return retmax;
    }
};

你可能感兴趣的:(力扣刷题,算法,算法)