栈
一、数组模拟栈
// tt表示栈顶int stk[N], tt = 0;// 向栈顶插入一个数stk[ ++ tt] = x;// 从栈顶弹出一个数tt -- ;// 栈顶的值stk[tt];// 判断栈是否为空if (tt > 0){}
二、单调栈
模板
常见模型:找出每个数左边离它最近的比它大/小的数int tt = 0;for (int i = 1; i <= n; i ++ ){while (tt && check(stk[tt], i)) tt -- ;stk[ ++ tt] = i;}
例题
https://www.acwing.com/activity/content/problem/content/865/
因为找出每个数左边离它最近的比它小的数,所以如果代表着若n[x]>=n[y],且x<y,那么n[x]不会被输出,所以使用单调栈,在往栈里存数据的时候,如果栈顶元素比当前元素大,则直接删去
import java.util.Scanner;public class Main{public static void main(String[] args) {Scanner in = new Scanner(System.in);int n = in.nextInt();int[] stk = new int[n];int tt = 0;for(int i = 0;i<n;i++) {int x = in.nextInt();while(tt != 0 && stk[tt] >= x) tt--;if(tt != 0) System.out.print(stk[tt]+" ");else System.out.print("-1 ");stk[++tt] = x;}}}
队列
一、数组模拟队列
1、普通队列
// hh 表示队头,tt表示队尾,q[]存的是下标int q[N], hh = 0, tt = -1;// 向队尾插入一个数q[ ++ tt] = x;// 从队头弹出一个数hh ++ ;// 队头的值q[hh];// 判断队列是否为空if (hh <= tt){}
2、循环队列
// hh 表示队头,tt表示队尾的后一个位置int q[N], hh = 0, tt = 0;// 向队尾插入一个数q[tt ++ ] = x;if (tt == N) tt = 0;// 从队头弹出一个数hh ++ ;if (hh == N) hh = 0;// 队头的值q[hh];// 判断队列是否为空if (hh != tt){}
二、单调队列(滑动窗口)O(nk)->O(n)
例题
https://www.acwing.com/problem/content/156/
思想
若用普通队列来做的话,每次移入元素进入窗口队列后,还要对窗口中的数进行遍历才能求出最值,遍历的时间复杂度是O(k),移动次数是n-k+1次,所以如果是普通队列,则时间复杂度为O(nk)
单调队列的思想来做这道题(求最大值的过程),视频讲解 ,优化后时间复杂度为O(n):
实现过程

核心代码(模板)
for (int i = 0;i<n;i++) {// q[hh]不在窗口[i-k+1, i]内,队头出队,每次出队只用出一个,所以用ifif (hh<=tt && q[hh] < i - k + 1) hh++;// 当前值<=队尾值,队尾出队 ,直到队空,所以用循环while (hh <= tt && a[q[tt]] <= a[i]) tt--;q[++ tt] = i;// 判断条件保证队列中有三个值。注意i是从0开始if (i >= k - 1) System.out.print(a[q[hh]] + " ");}
用deque实现
class Solution {public:vector<int> maxInWindows(vector<int>& nums, int k) {deque<int> q;vector<int> res;int n = nums.size();for(int i=0;i<n;i++) {if(q.size() && q.front() < i-k+1) q.pop_front();while(q.size() && nums[i] >= nums[q.back()]) q.pop_back();q.push_back(i);if(i>=k-1) res.push_back(nums[q.front()]);}return res;}};
