单调栈
1、应用场景
一般都是在一个数组中,一个数a,找到a左(右)边第一个大(小)于a的数
这类问题我们可以用暴力循环来做,直接从a开始循环,然后从左或者从右指定的元素即可。但是时间复杂度比较高,使用栈来优化。
2、例题
此题就是单调栈的经典应用,找出数组中每一个元素的左边第一个比他小的数
暴力做法
暴力做法就是双重循环,第一重遍历每个元素array[i]
,第二重循环从元素的左边第一个位置开始遍历,一直往前找,直到找到一个小于array[i]
的数返回,找不到输出-1
跟暴力做法基本一致的还可以使用一个栈,每遍历一个元素,就将它左边的元素从右往左全部入栈,然后一一的找小于目标元素的 单调栈优化的就是这种做法
,我们可以发现,当存在下面的关系时,则寻找y后面的元素的左边第一个最小值时,array[x]永远不会作为它的结果,所以我们就可以维护一个单调栈,是里面的元素永远是单调递增(减)的,这样每次遍历元素时,就不需要将其左边的元素全部入栈,而直接从栈中找答案即可。
x < y
array[x] > array[y]
单调栈示例
举例 :3 4 2 7 5
找出这个数组中每一个元素的左边第一个比他小的数。我们模拟一下过程
我们创建一个栈
------------------------------------------------------------------------------
3入栈
入栈时栈为空,说明3的左边没有比它小的数,然后将3入栈
此时栈中 3
------------------------------------------------------------------------------
4入栈
此时栈顶元素为3 比4小,所以4的结果就是3 然后将4入栈
此时栈中
4
3
------------------------------------------------------------------------------
2入栈
2比栈顶元素4小,说明2后面的数的答案就不可能是4了,将4出栈
然后栈顶时3 也比2小,同理也出栈 此时栈空,说明左边没有比2小的数
最后将2入栈
此时栈中 2
------------------------------------------------------------------------------
7入栈
7比栈顶元素2大,2就是7的答案,然后将7入栈
此时栈中
7
2
------------------------------------------------------------------------------
5入栈
5比栈顶元素7小,将7出栈,然后与2比较 大于2,那么2就是5的答案
最后将5入栈
此时栈中
5
2
经过上面的解释我们可以发现,栈中的元素从上到下一直都是单调递减的
,我们也不需要每次都将某一元素左边的元素全部入栈然后找答案,只需要维护一个单调栈然后直接去栈中找答案即可。核心就是靠上面的性质
代码
扫描二维码关注公众号,回复: 13358452 查看本文章
import java.util.Scanner;
import java.util.Stack;
public class Main{
public static void main(String[] args){
Stack<Integer> stack = new Stack();
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
for(int i = 0; i < n;i++){
int x = cin.nextInt();
//当栈不为空且x比栈顶元素大时栈顶元素出栈
while(!stack.isEmpty() && stack.peek() >= x ) stack.pop();
//栈为空时说明此元素前面没有比其小的数
if(stack.isEmpty())System.out.print(-1 + " ");
//不为空则此时的栈顶元素就是答案
else System.out.print(stack.peek()+" ");
//最后必须将此元素入栈
stack.push(x);
}
}
}
3、应用
力扣496.下一个更大元素 ——>题解
力扣503.下一个更大元素II——>双指针+单调栈
题解
力扣739.每日温度——>此题栈中存的是索引
题解