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

前言

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

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

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

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

单调栈

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

如果你看完了之后,绝对懂了。恭喜你。准备开始造火箭了
下面是一道经典的单调栈算法题

LeetCode|739. 每日温度

任务描述

  • 1\] 给定一个整数数组 `temperatures` ,表示每天的温度,

  • 3\] 其中 `answer[i]` 是指对于第 `i` 天,下一个更高温度出现在几天后。

示例 1:

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

示例 2:

ini 复制代码
输入: temperatures = [30,40,50,60]
输出: [1,1,1,0]

示例 3:

ini 复制代码
输入: 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。我们进行了许多重复的查找 有没有一种方法能解决这一点呢?在讲解单调栈解决问题之前,同学们可以先去思考一下看看有没有大概的思路锻炼自己的思维,没有的话也没事我开始也没想到。

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

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

下面是代码详解

代码实现

scss 复制代码
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;
};

结语

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

相关推荐
SweetCode5 分钟前
裴蜀定理:整数解的奥秘
数据结构·python·线性代数·算法·机器学习
喝拿铁写前端10 分钟前
智能系统的冰山结构
前端
z_mazin15 分钟前
JavaScript逆向魔法:Chrome开发者工具探秘之旅
javascript·chrome·爬虫
ゞ 正在缓冲99%…18 分钟前
leetcode76.最小覆盖子串
java·算法·leetcode·字符串·双指针·滑动窗口
绿草在线19 分钟前
Mock.js虚拟接口
开发语言·javascript·ecmascript
xuanjiong19 分钟前
纯个人整理,蓝桥杯使用的算法模板day2(0-1背包问题),手打个人理解注释,超全面,且均已验证成功(附带详细手写“模拟流程图”,全网首个
算法·蓝桥杯·动态规划
惊鸿.Jh38 分钟前
【滑动窗口】3254. 长度为 K 的子数组的能量值 I
数据结构·算法·leetcode
明灯L39 分钟前
《函数基础与内存机制深度剖析:从 return 语句到各类经典编程题详解》
经验分享·python·算法·链表·经典例题
碳基学AI1 小时前
哈尔滨工业大学DeepSeek公开课:探索大模型原理、技术与应用从GPT到DeepSeek|附视频与讲义免费下载方法
大数据·人工智能·python·gpt·算法·语言模型·集成学习
补三补四1 小时前
机器学习-聚类分析算法
人工智能·深度学习·算法·机器学习