目录
前言
单调栈是一种比较简单的数据结构。虽然简单,但在某些题目中能发挥很好的作用。
最近很多大厂的笔试、面试中都出现了单调栈的题目,而还有不少小伙伴连单调栈是什么都不了解,因此老汪专门写了这篇文章,希望对你们有所帮助。
老规矩,先上一道题给大家看看单调栈能解决什么样的问题,这题是 2020 年猿辅导(K12 教育的独角兽,研发岗白菜价 40W 起步,不加班高福利,想要内推的可以私信老汪)的一道面试题。
给定一个二叉搜索树,并给出他的前序序列,要求输出中序序列,时间复杂度O(n),并给出证明。
单调栈
- 是什么:单调栈是一种具有单调性的栈,任何时刻从栈顶到栈底的元素都是单调增/减的。
- 干什么:
- 单调栈可以找到从
左/右
遍历第一个
比它大/小
的元素的位置。 - 单调栈也可以将某个元素
左/右
边所有比它小/大
的元素按升/降序
输出。
- 单调栈可以找到从
- 怎么做:使用栈结构,在入栈的时候保持 id 和 val 的单调性即可。
翻译成大白话,凡是遇到题目中直接或间接要求查找某个元素左/右边第一个大于/小于它的元素,或者要求将某个元素左/右边所有小/大于它的元素按升/降序输出,就可以使用单调栈来解决。
具体怎么做你可能还有些迷糊,下面我们直接通过做题来加深对单调栈的理解。十分钟包教包会,当天就可以和面试官对线。
初入茅庐
给定数组 a,要求输出这样的数组 b,b[i] 是 a[i] 左边第一个比 a[i] 大的元素,若不存在则 b[i] = a[i]。
最暴力的解法,就是对每一个 a[i],遍历其左边的所有元素,这样所需的时间复杂度是 O(n^2)。如果使用单调栈,时间复杂度可以优化到 O(n)。
这是最基本、最直白的单调栈问题,所有单调栈问题都是在该问题上进行延伸、变种得来的,掌握了这个问题的解决方法,所有单调栈的问题都能迎刃而解。
由于本问题过于简单、直白,就不多做讲解,直接上代码:
public int[] solve(int[] a){
if(a == null) return null; //容错处理,越是简单的题越要注意细节
int n = a.length;
int[] b = new int[n];
Stack<Integer> stack = new Stack(); //单调栈当然要用栈结构啦
for(int i = 0; i < n; i++){
while(!stack.isEmpty() && stack.peek() < a[i]) stack.pop(); //所有比 a[i] 小的元素都出栈,保证了从栈顶到栈底元素是单调