算法模板之单调栈解密 | 图文详解


个人主页:聆风吟
系列专栏:算法模板、数据结构
少年有梦不应止于心动,更要付诸行动。


文章目录

  • 前言
  • 一. ⛳️单调栈讲解
    • 1.1 单调栈的定义
    • 1.2 如何维护一个单调栈
    • 1.3 单调栈的用途
    • 1.4 模板总结(重点)
    • 1.4 单调栈的实例练习
  • 全文总结

前言

     hello! 各位铁子们大家好哇,今天作者给大家带来了单调栈的算法解密,因为前面我们已经讲解了用数组模拟栈过程,今天单调栈也是采用数组模拟,在此就不多做叙述有需要补漏的小伙伴可以自行前往下面专栏去浏览。
     系列专栏:本期文章收录在《算法模板》,大家有兴趣可以浏览和关注,后面将会有更多精彩内容!
     欢迎大家关注点赞收藏⭐️留言



一. ⛳️单调栈讲解

1.1 单调栈的定义

定义:栈内的元素是单调递增或单调递减的栈。


1.2 如何维护一个单调栈

  • 单调递增栈:在保持栈内元素单调递增的前提下,如果栈顶元素大于要入栈的元素,将栈顶元素弹出,将新元素入栈。
  • 单调递减栈:在保持栈内元素单调递减的前提下,如果栈顶元素小于要入栈的元素,则将栈顶元素弹出,将新元素入栈。

1.3 单调栈的用途

算法模板之单调栈解密 | 图文详解_第1张图片

由上图可以看出,对于栈内元素来说:

  • 在栈内左边的数就是数组中左边第一个比自己小的元素;
  • 但元素被弹出时,遇到的就是数组中右边第一个比自己小的元素。

对于将要入栈的元素来说:在对栈进行更新后(即弹出了所有比自己大的元素),此时栈顶元素就是数组中左侧第一个比自己小的元素;


算法模板之单调栈解密 | 图文详解_第2张图片

由上图可以看出,对于栈内元素来说:

  • 在栈内左边的数就是数组中左边第一个比自己大的元素;
  • 但元素被弹出时,遇到的就是数组中右边第一个比自己大的元素。

对于将要入栈的元素来说:在对栈进行更新后(即弹出了所有比自己小的元素),此时栈顶元素就是数组中左侧第一个比自己大的元素;

    由此,我们可以看出单调栈的用途是:给定一个序列,指定一个序列中的元素,求解该元素左侧或右侧第一个比自己小或大的元素。

1.4 模板总结(重点)

本文总结的模板是找出每个数左边离它最近的比它大或小的数,右边的可以自行推导(单看模板比较抽象,建议看完下面的题目,在返回来看)

//常见模型:找出每个数左边离它最近的比它大/小的数
int tt = 0;//栈顶指针
for (int i = 1; i <= n; i ++ )
{
    //check函数是判断查找:
    //1. 每个数左边第一个比它小的数
    //2. 还是每个数左边第一个比它大的数
    while (tt && check(stk[tt], i)) tt -- ;
    stk[ ++ tt] = i;
}

1.4 单调栈的实例练习

⌈ 在线OJ链接 ⌋

题目:
算法模板之单调栈解密 | 图文详解_第3张图片

输入样例:

5
3 4 2 7 5

输出样例:

-1 3 -1 2 2

解题思路:
    我们还是以上面的 3 4 2 7 5 来举例分析,开始遍历 3 这个元素,此时栈为空,那就表明 3 这个元素左侧没有比自身小的元素,将结果 -1 记录一下(或者直接输出)。然后将 3 压入栈中。遍历到 4 时发现 4 大于栈顶的元素 3,表明 4 这个元素左侧第一个比自身小的元素是 3,将结果 3 记录一下(或者直接输出)。遍历到 2 时,发现 2 小于栈顶的元素 4,4 是不可能作为结果输出的,所以需要将栈顶的 4 弹出。弹出之后栈顶的元素就是 3 ,同样 2 仍然小于 3,需要再次将 3 弹出。此时我们发现栈里面已经没有元素了,说明 2 的左侧没有比自身小的元素,将结果 -1 记录一下。然后将 2 压入栈中。其他的元素同理便可以得出,下面给出了动图,这里就不一一讲解了!
算法模板之单调栈解密 | 图文详解_第4张图片

c++代码:

#include 

using namespace std;
const int N = 100010;
int stk[N], tt;

int main()
{
    int n = 0;
    cin >> n;
    
    for(int i = 0; i < n; i++)
    {
        int x = 0;
        cin >> x;
        
        //如果栈顶元素大于当前待入栈元素,则出栈
        while(tt && stk[tt] >= x) tt--;
        
        if(tt)
        {
            //栈顶元素就是左侧第一个比它小的元素。
            cout << stk[tt] << " ";
        }
        else 
        {
            //如果栈空,则没有比该元素小的值。
            cout << "-1" << " ";
        }
        
        //将当前元素加入单调栈中
        stk[++tt] = x;
    }
    
    return 0;
}


全文总结

本文主要讲解:

  1. 单调栈的定义:栈内的元素是单调递增或单调递减的栈;
  2. 如何维护一个单调栈;
  3. 单调栈的用途:给定一个序列,指定一个序列中的元素,求解该元素左侧或右侧第一个比自己小或大的元素;
  4. 实例练习

     文章可能会有出现错误的地方,欢迎大家在评论区里指正,非常感谢。同时希望大家课下能够多敲多练,孰能生巧。

     今天的内容就到这里了,你对今天的内容是否有所掌握?如果还有疑问的话请在评论区里多多提问,大家可以一起帮你解决,让我们共同进步。创作不易,如果对你有用的的话点个赞支持下作者,你们的支持是作者创作最大的动力。关注我不迷路,让我们下期再见✋✋。

你可能感兴趣的:(算法模板,c++,算法,数据结构)