【算法基础7】求最值问题总是超时?试一试单调栈和单调队列

一、单调栈

        主要思想:在找某一数左边大于它或小于它值时,常规算法中的双循环每次都要从头开始遍历,比较了很多没有可能的数,导致算法超时。改用单调栈后,每次都和栈顶元素比较,如果栈顶元素不满足当前条件,即不是现有栈中的最大最小值,也必然不可能是加上下一个数后的新栈中的最大最小值,那么这个元素就没有必要再进行比较,直接出栈,不断重复直到栈顶元素满足最大最小条件后停止。每次遍历都对栈进行此操作就能使栈中元素具有单调性,找最值时直接输出栈顶元素,大大节省了计算时间。

        例题:给一个长为n的数组,输出每个数左边第一个小于它的数,如果不存在则输出-1。

#include<iostream>
using namespace std;

const int N=1000;
int stk[N];
int tt;

int main(){
	int n;
	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;
	}
	return 0;
}

二、单调队列

        主要思想:在滑动窗口中找最大最小值,改用思想类似单调栈,为了模拟窗口大小增加队头指针使用单调队列。需要注意窗口大小有限制,要根据窗口大小及时移动队头,在变量数还不够窗口大小时不进行答案输出。

        例题:给一个长为n的数组,有一个大小为k的滑动窗口,每次输出窗口中最大的数。

#include<iostream>
using namespace std;

const int N=1000;
int a[N],q[N];
int hh,tt;

int main(){
	int n,k;
	scanf("%d %d",&n,&k);
	for(int i=0;i<n;i++) scanf("%d",&a[i]);

	hh=0;//队头、队尾指针初始化
	tt=-1;
	for(int i=0;i<n;i++){
		if(hh<=tt&&i-k+1>q[hh]) hh++;//向右移动滑动窗口
		while(hh<=tt&&a[q[tt]]>=a[i]) tt--;//注意单调队列q[]中储存的是下标
		q[++tt]=i;
		if(i>=k-1) printf("%d ",a[q[hh]]);//填满滑动窗口后再进行答案输出
	}
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值