单调栈-(滑动窗口)

算法原理:
用单调递增栈,当该元素可以入栈的时候,栈顶元素就是它左侧第一个比它小的元素。
以:3 4 2 7 5 为例,过程如下:(小到大)

AcWing 830. 单调栈 - AcWing

#include<iostream>
using namespace std;
const int N=1e6+5;
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) {
			//说明左边没有比他大的
			cout<<-1<<" ";
		} else {
			cout<<stk[tt]<<" ";
		}
		stk[++tt]=x;
	}
	return 0;
}

 

 154. 滑动窗口 - AcWing题库

解题思路(以最大值为例):

由于我们需要求出的是滑动窗口的最大值。

如果当前的滑动窗口中有两个下标 i 和 j ,其中i在j的左侧(i<j),并且i对应的元素不大于j对应的元素(nums[i]≤nums[j]),则:

当滑动窗口向右移动时,只要 i 还在窗口中,那么 j 一定也还在窗口中。这是由于 i 在 j 的左侧所保证的。

因此,由于 nums[j] 的存在,nums[i] 一定不会是滑动窗口中的最大值了,我们可以将nums[i]永久地移除。

因此我们可以使用一个队列存储所有还没有被移除的下标。在队列中,这些下标按照从小到大的顺序被存储,并且它们在数组nums中对应的值是严格单调递减的。

当滑动窗口向右移动时,我们需要把一个新的元素放入队列中。

为了保持队列的性质,我们会不断地将新的元素与队尾的元素相比较,如果新元素大于等于队尾元素,那么队尾的元素就可以被永久地移除,我们将其弹出队列。我们需要不断地进行此项操作,直到队列为空或者新的元素小于队尾的元素。

由于队列中下标对应的元素是严格单调递减的,因此此时队首下标对应的元素就是滑动窗口中的最大值。

窗口向右移动的时候。因此我们还需要不断从队首弹出元素保证队列中的所有元素都是窗口中的,因此当队头元素在窗口的左边的时候,弹出队头。

#include<iostream>
#include<deque>
#include<algorithm>
using namespace std;
const int N=1e6+5;
int a[N],q[N],hh,tt=-1;

int main() {
	int n,k;
	cin>>n>>k;
	for(int i=1; i<=n; i++) {
		scanf("%d",&a[i]);
	}
	deque<int>q;
	for(int i=1; i<=n; i++) {
		while(q.size()&&q.back()>a[i]) {
			//新进入窗口的值小于队尾元素
			q.pop_back();
		}
		q.push_back(a[i]);//将新元素入队
		if(i-k>=1&&q.front()==a[i-k]) {
			//判断队头是否滑出了窗口
			//队头出列
			q.pop_front();
		}
		if(i>=k)//窗口i形成了,输出队头对应的值
			cout<<q.front()<<" ";
	}
	q.clear();//清空队列
	cout<<endl;
	for(int i = 1; i <= n; i++) {
		while(q.size() && q.back() < a[i]) q.pop_back();//新进入的元素大于队尾元素
		q.push_back(a[i]);
		if(i - k >= 1 && a[i - k] == q.front())
			q.pop_front();//判断队头是否出列
		if(i >= k) cout << q.front() << " ";
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值