模拟队列
什么是队列?
- 就是一个特殊的数组。这个数组,最前面叫队头,最后面叫队尾。只允许在最后面添加元素,只允许在最前面删除元素。
题目
实现一个队列,队列初始为空,支持四种操作:
- push x – 向队尾插入一个数 x ;
- pop – 从队头弹出一个数;
- empty – 判断队列是否为空;
- query –查询队头元素。
现在要对队列进行 M 个操作,其中的每个操作 3 和操作 4 都要输出相应的结果。
输入格式 第一行包含整数 M ,表示操作次数。
接下来 M 行,每行包含一个操作命令,操作命令为 push x,pop,empty,query 中的一种。
输出格式 对于每个 empty 和 query 操作都要输出一个查询结果,每个结果占一行。
其中,empty 操作的查询结果为 YES 或 NO,query 操作的查询结果为一个整数,表示队头元素的值。
数据范围 、 1≤M≤100000 , 1≤x≤109 , 所有操作保证合法。
输入样例: 10 push 6 empty query pop empty push 3 push 4 pop query push 6 输出样例: NO 6 YES 4
解题思路:
-
用一个数组
q保存数据。 -
用
hh代表队头,q[hh]就是队头元素,q[hh + 1]就是第二个元素。 -
用
tt代表队尾,q[tt]就是队尾元素,q[tt + 1]就是下一次入队,元素应该放的位置。 -
[hh, tt]左闭右闭,代表队列中元素所在的区间。 -
出队
pop:因为hh代表队头,[hh, tt]代表元素所在区间。所以出队可以用hh++实现,hh++后,区间变为[hh + 1, tt]。 -
入队
push:因为tt代表队尾,[hh, tt]代表元素所在区间。所以入出队可以用tt++实现,tt++后,区间变为[hh, tt + 1],然后在q[tt+1]位置放入入队元素。 -
是否为空
empty:[hh, tt]代表元素所在区间,当区间非空的时候,对列非空。也就是tt >= hh的时候,对列非空。 -
询问队头
query:用hh代表队头,q[hh]就是队头元素,返回q[hh]即可。
代码
#include <iostream>
using namespace std;
const int N = 100010;
int q[N];
//[hh, tt] 之间为队列(左闭右闭)
int hh = 0;//队头位置
int tt = -1;//队尾位置
//操作次数
int m;
//操作方式
string s;
//入队:队尾先往后移动一格,再放入要插入的数据
void push(int x){
q[++tt] = x;
}
//出队:队头往后移动一格
void pop(){
hh++;
}
//[hh, tt]表示队列区间,当tt >= hh时,区间不为空
void empty(){
if(tt >= hh) cout << "NO" << endl;
else cout << "YES" << endl;
}
//hh指向队头,q[hh]代表队头元素
void query (){
cout << q[hh] << endl;
}
int main(){
cin >> m;
while(m--){
cin >> s;
//入队
if(s == "push"){
int x;
cin >> x;
push(x);
}
//出队
if(s == "pop"){
pop();
}
//问空
if(s == "empty"){
empty();
}
//问队头
if(s == "query"){
query();
}
}
}
Java
import java.util.Scanner;
public class Main{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
int m = scan.nextInt();
//队列是在tt队尾插入元素,队头hh弹出元素
int[] dl = new int[100010];
int hh = 0;
int tt = -1;
while(m -- > 0){
String s = scan.next();
if(s.equals("push")){
int x = scan.nextInt();
dl[++tt] = x;
}else if(s.equals("pop")){
hh++;
}else if(s.equals("empty")){
if(hh <= tt) System.out.println("NO");
else System.out.println("YES");
}else {
System.out.println(dl[hh]);
}
}
}
}
单调栈
给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1 。
输入格式 第一行包含整数 N ,表示数列长度。
第二行包含 N 个整数,表示整数数列。
输出格式 共一行,包含 N 个整数,其中第 i 个数表示第 i 个数的左边第一个比它小的数,如果不存在则输出 −1 。
数据范围 1≤N≤10^5^
1≤数列中元素≤10^9^ 输入样例: 5 3 4 2 7 5 输出样例: -1 3 -1 2 2
算法原理:
用单调递增栈,当该元素可以入栈的时候,栈顶元素就是它左侧第一个比它小的元素。 以:3 4 2 7 5 为例,过程如下:
代码:
//cpp
#include <iostream>
using namespace std;
const int N = 100010;
int stk[N], tt;
int main()
{
int n;
cin >> n;
while (n -- )
{
int x;
scanf("%d", &x);
while (tt && stk[tt] >= x) tt -- ;//如果栈顶元素大于当前待入栈元素,则出栈
if (!tt) printf("-1 ");//如果栈空,则没有比该元素小的值。
else printf("%d ", stk[tt]);//栈顶元素就是左侧第一个比它小的元素。
stk[ ++ tt] = x;
}
return 0;
}
Java
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
int n = scan.nextInt();
int[] stk = new int[100010];
int tt = 0;
for(int i = 0 ; i < n ; i++ ){
int x = scan.nextInt();
//如果栈是空的,栈顶元素大于等于x,那么就说明栈顶这个数明显没有x好,
//因为比较的是左边第一个最近最小的数,所以就把stk[tt]弹出了;
while(tt!=0 && stk[tt] >= x){
tt--;
}
//如果弹出操作完了之后,栈不是空的,就输出栈顶元素,
if(tt != 0) System.out.print(stk[tt]+" ");
//否则就是栈是空的,输出-1
else System.out.print("-1" + " ");
//最后将x插入栈顶;
stk[++tt] = x;
}
}
}