面试高频算法系列第一篇章:单调栈(思路+解题步骤详解)

前言

在学习最小栈算法之前我们必须知道何为,何为单调栈

简单来说在JS就是一个数组,只拥有pushpop方法,或者只拥有shiftunshift方法。
实现先进后出的效果。例如:

栈先添加1再添加2,此时调用栈的弹出方法,应该先弹出2,再弹出1。

在这里插入图片描述

如上图,因为底部被封住了。所以1这个元素只能从上边出口出栈,而因为2这个元素挡着了所以1无法出栈,必须先弹出2,1才能进行出栈操作

单调栈

单调栈是一种特殊的数据结构,其特点是栈内的元素按照一定的单调性排列,可以是单调递增或单调递减。就和数组排列是顺序或者逆序是一个道理。

如果你看完了之后,绝对懂了。恭喜你。准备开始造火箭了


下面是一道经典的单调栈算法题

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/9f18ded730704bd39c412b8a75a116a3.jpeg#pic_center

LeetCode|739. 每日温度

任务描述

  • [1] 给定一个整数数组 temperatures ,表示每天的温度,
  • [2] 返回一个数组 answer
  • [3] 其中 answer[i] 是指对于第 i 天,下一个更高温度出现在几天后。
  • [4] 如果气温在这之后都不会升高,请在该位置用 0 来代替。

示例 1:

输入: temperatures = [73,74,75,71,69,72,76,73]
输出: [1,1,4,2,1,1,0,0]

示例 2:

输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]

示例 3:

输入: temperatures = [30,60,90]
输出: [1,1,0]

提示:

  • 1 <= temperatures.length <= 105
  • 30 <= temperatures[i] <= 100

看到这里可以自己先去LeetCode写写这题,大标题就是这题的链接。不会的话可以回来看题解。

代码实现思路

  1. 实现问题之前一定要明确目标,这题的问题是让你求这个数下一个比他大的数的下标-自己的下标值,没有则赋值0

  2. 没好的想法之前看看暴力能不能解决,这题显然暴力是可以实现要求的。每到一个新的值时候通过for循环
    来寻找较大数的下标。ok,这题讲完了。下课(咳咳开个玩笑)当写完之后,我们就应该来思考能不能对代码进行优化

  3. 我们发现,在每次到一个新的值时,我们都要往后进行遍历寻找,有时候几个值往后找的较大值是同一个。
    例如:[2,2,2,3]这个数组我们可以知道前面的三个二,后面的较大数都是3。我们进行了许多重复的查找
    有没有一种方法能解决这一点呢?在讲解单调栈解决问题之前,同学们可以先去思考一下看看有没有大概的思路锻炼自己的思维,没有的话也没事我开始也没想到。hj.jpg

4.我们开始思考,突然灵光一闪发现单调栈好像可以实现我们想要的效果(其实不是灵光一闪,我直接看的解析说要用单调栈)。为什么可以实现呢?还是拿[2,2,2,3]举例,我们在每一次遍历遇到新的值这里进行判断,这个新的值是否能满足之前的还没有较大数的值的要求(是否是 0 - i-1这个区间里还没有较大值的数,新的值为他们的较大值)。

image.png

每次遍历到新的值时,都对还没有较大数的值进行判断。不断更新,知道数组遍历完全,这样所有拥有较大值的数的找到了他们的较大值数下标。而还没有找到较大值的数则赋值为0.而实现上诉代码的数据结构就用单调栈,每次元素遍历时进行单调栈内的未找到最大值元素进行判断是否更新,更新完然后入栈。这里要注意的是,在使用单调栈存储元素时,因为题目要求的是下标,所以单调栈存储的时候也是要存下标
下面是代码详解

代码实现

var dailyTemperatures = function(temperatures) {
    //初始化全部为0,省去了最后为 increaseStack
    //中剩余的每个元素在result数组中添加一个 0
    let result = new Array(temperatures.length).fill(0);
    //单调递增栈
    let increaseStack = [];
    //首元素的添加
    increaseStack.push(0);
    for (let i = 1; i < temperatures.length; i++) {
    //一直更新到,发现单调栈内的最小元素都比自己大的时候停止更新
        while (increaseStack.length > 0 && temperatures[i] > temperatures[increaseStack[increaseStack.length - 1]]) {
        // 被更新的元素从单调栈内弹出,
        //因为已经找到了最近的较大值。后续不再需要操作
            let prevIndex = increaseStack.pop();
            //存储答案
            result[prevIndex] = i - prevIndex;
        }
        //遍历的元素还没开始找,所以放入单调栈中。、
        //由后面的元素来决定是否进行进行元素更新弹栈操作
        increaseStack.push(i);
    }
    //返回最终结果
    return result;
};

结语

因为是第一次写算法讲解和思路,所以可能会有些比较晦涩。如果你有疑惑的话,欢迎私信或者评论区地下留言。我都会一一回复。好了,如果喜欢这篇文章的话,请点个赞吧!后续还会更新算法讲解的哦!

  • 28
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

绯雨934

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值