携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第6天,点击查看活动详情
单调栈
什么是单调栈?
-
从名字上就听的出来,单调栈中存放的数据应该是有序的,所以单调栈也分为单调递增栈和单调递减栈
- 单调递增栈:单调递增栈就是从栈底到栈顶数据是从大到小
- 单调递减栈:单调递减栈就是从栈底到栈顶数据是从小到大 模拟单调栈的数据push和pop
-
模拟实现一个递增单调栈:
现在有一组数10,3,7,4,12。从左到右依次入栈,则如果栈为空或入栈元素值小于栈顶元素值,则入栈;否则,如果入栈则会破坏栈的单调性,则需要把比入栈元素小的元素全部出栈。单调递减的栈反之。
10入栈时,栈为空,直接入栈,栈内元素为10。
3入栈时,栈顶元素10比3大,则入栈,栈内元素为10,3。
7入栈时,栈顶元素3比7小,则栈顶元素出栈,此时栈顶元素为10,比7大,则7入栈,栈内元素为10,7。
4入栈时,栈顶元素7比4大,则入栈,栈内元素为10,7,4。
12入栈时,栈顶元素4比12小,4出栈,此时栈顶元素为7,仍比12小,栈顶元素7继续出栈,此时栈顶元素为10,仍比12小,10出栈,此时栈为空,12入栈,栈内元素为12。
用途:主要找到每个数左边离他最近的且比它小的数在什么地方(或者找到每个数右边离他最近的且比它大的数在什么地方)
题目
给定一个长度为 N 的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
输入格式
第一行包含整数 N,表示数列长度。
第二行包含 N 个整数,表示整数数列。
输出格式
共一行,包含 N 个整数,其中第 i 个数表示第 i 个数的左边第一个比它小的数,如果不存在则输出 −1。
数据范围
1≤ N ≤ 105
1≤ 数列中元素 ≤ 109输入样例:
5 3 4 2 7 5输出样例:
-1 3 -1 2 2
方法一:暴力解法
for (int i = 0; i < n; i ++)
for (int j = i - 1; j >= 0; j --)
if (a[i] > a[j])
{
cout << a[j] << endl;
break;
}
#include <iostream>
using namespace std;
const int N = 100010;
int q[N];
int n;
int main()
{
cin >> n;
for (int i = 0; i < n; i ++) cin >> q[i];
for (int i = 0; i < n; i ++)
{
int j = i - 1;
for (; j >= 0; j --)
{
if (q[j] < q[i])
{
cout << q[j]<<" ";
break;
}
}
if (j < 0)
{
cout << "-1" <<" ";
}
}
return 0;
}
方法二:优化
- 用栈存储 i 左边的元素
- 如果 ax >= ay,并且x < y那么ax永远不会输出,就直接可以删除。(只要有这种逆序的关系,前面的数就会被删掉,此时剩下的序列就是单调序列了)
#include <iostream>
using namespace std;
const int N = 100010;
int n;
int stk[N], tt;
int main()
{
cin >> n;
for (int i = 0; i < n; i ++)
{
int x;
cin >> x;
while (tt && stk[tt] >= x) tt -- ;
if (tt) cout << stk[tt] << " ";
else cout << "-1" << " ";
stk[ ++ tt] = x;
//cout << tt << endl;;
}
return 0;
}