microsee 单调栈

前言

单调栈,理解起来很简单,实现起来也不难,但是具体应用起来,还有点不容易。 刷leeCode的时候做到了好几个关于单调栈的题,简单总结一波,希望可以便人便己。


一、什么是单调栈?

首先单调栈是一种数据结构,更确切的说,它是一种栈。普通的栈结构,可以在任意时刻进行入栈、出栈(当然,入栈时要保证栈不满、出栈时栈不能空)。而对于单调栈来说,其需要保证栈内元素的有序性(递增、递减或者其他的规则),入栈和出栈操作需要受到一定的限制。

如下图所示:
在这里插入图片描述

二、单调栈用于何处?

参考【1】中的评论对于这点介绍的比较清晰。 摘录如下:

单调栈性质:

  1. 单调栈里的元素具有单调性。
  2. 递增(减)栈中可以找到元素左右两侧比自身小(大)的第一个元素。

我们主要使用第二条性质 (也就是说我们更关注的是栈元素入栈和出栈的时刻,而不是任意时刻栈中元素的有序性),该性质主要体现在栈调整过程中。下面以递增栈为例(假设所有元素都是唯一),当新元素入栈。

  • 对于出栈元素来说:找到右侧第一个比自身小的元素。
  • 对于新元素来说:等待所有破坏递增顺序的元素出栈后,找到左侧第一个比自身小的元素。

三、举例

下面简单举一个leecode中的例子进行说明。

3.1 题目描述

如下:
在这里插入图片描述

3.2 解法

如果有了上面单调栈的了解和铺垫,这题就很简单了。 求指定元素的右边第一个大的元素,和我们在第2节中说的类似,只不过为了我们得把递增栈换成递减栈。

代码如下:

class Solution {
public:
    vector<int> nextGreaterElement(vector<int>& nums1, vector<int>& nums2) {

        vector<int> ans;
        unorder_map<int,int> greatMap;

        stack<int> greatSta;
		
		nums2.push_back(INT_MAX);
		
        for(int i = 0;i<nums2.size();++i){
			
			while(greatSta.empty() == false){
				int tmpTop = greatSta.top();
				
				if(tmpTop<nums2[i]){
					
					greatMap[tmpTop] = nums2[i];
					greatSta.pop();
				}else{
					break;
				}
			}
			
			greatSta.push(nums2[i]);
           
        }
		
		//收集
		for(auto num:nums1){
			
			if(greatMap.count(num) > 0){
				
				if(greatMap[num] ==INT_MAX){
					ans.push_back(-1);
				}else{
					ans.push_back(greatMap[num]);
				}
			}
		}
        return ans;
    }
};

 
还有一些比较经典的单调栈的题型,这里就不说了。关键点就是从题目中分析出可以使用单调栈的性质出来。

三、总结

一般情况下,单调栈多用于一维序列之中。主要是以比较快的方式(O(1))找到指定元素左右两侧比他大(或小)的数的位置(一般情况下,我们都找第一个)。

具体对于某一个元素来说,入栈能确定与其左边元素(最接近的)的关系(递增栈是小于,递减栈是大于)。出栈可以确定与其右边元素(最接近)的关系(递增栈是小于,递减栈是大于)。

好了,基本就这些了,理论完了,还是实操一下比较好。


参考

【1】、刷题笔记6(浅谈单调栈)
【2】、496. 下一个更大元素 I

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值