单调栈和单调队列的使用场景都不是很多,仅限于特定的题目。
单调栈:
单调栈一般用来以O(n)的时间复杂度找到第i个数左边或者右边最近且最大/最小的数。
举例:遍历一个数组,对于每个元素m,找到左边离当前元素最近且大于当前元素值的下标。
通用代码模板:
//找到当前元素左边的最近的比他小的元素的下标
Deque<Integer> stack = new ArrayDeque<>();
for(int i = 0;i<n;i++) {
int x = scanner.nextInt();
while (!stack.isEmpty() && stack.peek() >= x) {
stack.pop();
}
System.out.print(stack.isEmpty()?-1:stack.peek());
相关题目:活动 - AcWing 系统讲解常用算法与数据结构,给出相应代码模板,并会布置、讲解相应的基础算法题目。https://www.acwing.com/problem/content/832/
参考题解:
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner (System.in);
int n = sc.nextInt();
Deque<Integer> stack = new ArrayDeque<>();
for(int i = 0;i<n;i++) {
int x = sc.nextInt();
while (!stack.isEmpty() && stack.peek() >= x) {
stack.pop();
}
System.out.print(stack.isEmpty()?-1:stack.peek());
System.out.print(" ");
stack.push(x);
}
}
}
单调队列:
和单调栈类似。典型的题目是滑动窗口。给定一个数组和数组长度,再给一个滑动窗口的长度。滑动窗口每次往后移动一格。求出每次滑动窗口中的最小值或者最大值。
通用代码模板:
Deque<Integer> min= new ArrayDeque<>();
for(int i = 0;i<n;i++) {
//判断当前下标是否还在滑动窗口内,若不在滑动窗口内,则从队头出队列
if (!min.isEmpty() && min.peekFirst()+k-1<i) {
min.pollFirst();
}
//若当前元素小于队尾元素,则队尾元素一定不会作为答案输出。
//将队尾元素出队列。直到队尾元素小于当前元素,当前元素入队列。
while (!min.isEmpty() && a[min.peekLast()] >= a[i]) {
min.pollLast();
}
//当前元素入队列
min.offer(i);
//输出队头元素,因为当前队列是递增的,滑动窗口的最小值出现在队头。
if (i >= k-1) {
pw.print(a[min.peekFirst()] + " ");
}
}
相关题目:154. 滑动窗口 - AcWing题库高质量的算法题库https://www.acwing.com/problem/content/156/参考题解:
import java.io.*;
import java.util.*;
public class Main{
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String[] s = br.readLine().split(" ");
int n = Integer.parseInt(s[0]);
int k = Integer.parseInt(s[1]);
int[] a = new int[n];
Deque<Integer> max = new ArrayDeque<>();
Deque<Integer> min = new ArrayDeque<>();
PrintWriter pw = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
String[] s1 = br.readLine().split(" ");
for(int i = 0;i<n;i++) {
a[i] = Integer.parseInt(s1[i]);
}
for(int i = 0;i<n;i++) {
if (!min.isEmpty() && min.peekFirst()+k-1<i) {
min.pollFirst();
}
while (!min.isEmpty() && a[min.peekLast()] >= a[i]) {
min.pollLast();
}
min.offer(i);
if (i >= k-1) {
pw.print(a[min.peekFirst()] + " ");
}
}
pw.println();
for(int i = 0;i<n;i++) {
if (!max.isEmpty() && max.peekFirst()+k-1<i) {
max.pollFirst();
}
while (!max.isEmpty() && a[max.peekLast()] <= a[i]) {
max.pollLast();
}
max.offer(i);
if (i >= k-1) {
pw.print(a[max.peekFirst()] + " ");
}
}
pw.flush();
}
}