版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
一、介绍
栈是一种“先进后出” 或 “后进先出”的线性数据结构。栈只有一端能够进出元素,我们一般称这一端为栈顶,另一端为栈底。添加或者删除栈中的元素时,我们只能将其插入到栈顶(进栈),或者把栈顶元素从栈中取出(出栈)。
二、Push,Pop,GetMin
- 题目: 实现一个栈,支持Push(入栈)、Pop(出栈并输出栈顶) 和 GetMin(查询栈中最小的值)三个操作,要求时间复杂度为O(1)。
- 思路: 栈结构原本就支持O(1)的入栈、出栈操作,但不支持查询最小值的操作。我们再用一个栈来保存历史上每个时刻的最小值。
我们建立两个栈,栈A存储原本的数据,栈B存储A中以栈底开头的每段数据的最小值。
如:
A:9 2 1 5 3 0 2 <-----
B:9 2 1 1 1 0 0 <-----
当执行Push(x)操作时,在A中插入x,在B中插入min(B的栈顶数据,x)。在执行Pop操作时,在A、B分别弹出栈顶。执行getMin的时候直接输出栈顶元素。 - 代码:
#include <cstdio> #include <algorithm> using namespace std; const int N = 1e6 + 5; int A[N], B[N], n, m, x; int top;//代表栈顶 void push(int x) { A[top] = x; if (top == 0) { B[top] = x; } else { B[top] = min(B[top - 1], x); } top++; } void pop() { top--; } int getMin() { return B[top - 1]; } int main() { scanf("%d%d", &n, &m); for (int i = 0; i < n; i++) { scanf("%d", &x); push(x); } for (int i = 0; i < m; i++) { scanf("%d", &x); if (x == 1) { pop(); } else { printf("%d\n", getMin()); } } return 0; }
三、单调栈
-
基础的栈和队列大家已经都了解了,单调栈唯一的不同就是额外维护栈内元素的一个单调性。怎么维护呢?也就是在压入元素之前我们先弹出若干个元素,直到单调性得到了保证。
例题:
给定一个长度为N的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出-1。输入样例:
5
3 4 2 7 5输出样例:
-1 3 -1 2 2
例题入口
-
思路: 用单调栈维护一个序列的单调性,每次将输入的数x压入栈之前,先判断栈顶是否小于x,若不小于弹出若干元素直到栈顶元素小于x或者栈空。然后若栈空输出-1,否则输出栈顶元素,最后x入栈。
-
代码:
#include <cstdio> const int N = 1e5 + 5; int st[N], n, top, x; void push(int x) { while (top != 0 && st[top - 1] >= x) { top--; } if (top == 0) { printf("-1 "); } else { printf("%d ", st[top - 1]); } st[top++] = x; } int main() { scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &x); push(x); } return 0; }