单调栈
题目
给定一个长度为 N的整数数列,输出每个数左边第一个比它小的数,如果不存在则输出 −1。
输入格式
第一行包含整数 N,表示数列长度。
第二行包含 N个整数,表示整数数列。
输出格式
共一行,包含 N个整数,其中第 i个数表示第 i个数的左边第一个比它小的数,如果不存在则输出 −1。
数据范围
1≤N≤105
1≤数列中元素≤109
输入样例:
5
3 4 2 7 5
输出样例:
-1 3 -1 2 2
代码实现
1.vector实现
#include<iostream>
#include<vector>
using namespace std;
vector<int>a;
int main()
{
int n;
scanf("%d",&n);
while(n--)
{
int x;
scanf("%d",&x);
while(a.size()>0&&a.back()>=x)
{
a.pop_back();
}
if(a.size()==0)
{
printf("-1 ");
}
else
{
printf("%d ",a.back());
}
a.push_back(x);
}
return 0;
}
2.stack实现
#include<iostream>
#include<stack>
using namespace std;
int main()
{
stack<int>a;
int n;
scanf("%d",&n);
while(n--)
{
int x;
scanf("%d",&x);
while(a.size()>0&&a.top()>=x)
{
a.pop();
}
if(a.size()==0)
{
printf("-1 ");
}
else
{
printf("%d ",a.top());
}
a.push(x);
}
return 0;
}
3.数组模拟实现
#include<iostream>
using namespace std;
const int N = 1e5 + 10;
int index, e[N];
int main()
{
int n;
cin >> n;
while(n -- )
{
int x;
scanf("%d", &x);
while(index != 0 && e[index] >= x)
{
index -- ;
}
if(index == 0)
{
printf("-1 ");
}
else
{
printf("%d ", e[index]);
}
e[++ index] = x;
}
return 0;
}
单调队列(滑动窗口)
题目
代码实现
#include<iostream>
using namespace std;
const int N = 1e6 + 10;
int q[N], head = 0, tail = -1, a[N];//q[]是用来记录数组的head、tail位置的下标 a[]是用来读入数组
//head在左侧,tail在右侧
int main()
{
int n, k;
cin >> n >> k;
for(int i = 0;i < n;i ++ )//强烈建议i从0开始,便于判断head节点是否滑出窗口
{
scanf("%d", &a[i]);
}
//下面为单调增数列,每次只需输出a[q[head]]即可输出窗口中最小值
for(int i = 0;i < n;i ++ )
{
if(i - k == q[head])//列个简单的数组放进题目中试试,就会得到这一判断头节点是否滑出窗口的条件
//i若是从1开始就要加入很多特判防止i=1,k=1的时候从一开始就错误head++!!
{
head ++ ;
}
while(head <= tail && a[i] <= a[q[tail]])//tail >= head是保证窗口不为空
{
tail -- ;
}
q[ ++ tail] = i;
if(i + 1 >= k)
{
printf("%d ", a[q[head]]);
}
}
cout << endl;
head = 0, tail = -1;//重置条件
for(int i = 0;i < n;i ++ )
{
if(i - k == q[head])
{
head ++ ;
}
while(head <= tail && a[i] >= a[q[tail]])
{
tail -- ;
}
q[ ++ tail] = i;
if(i + 1 >= k)
{
printf("%d ", a[q[head]]);
}
}
return 0;
}