单调栈&单调队列

单调栈

什么是单调栈,从字面意思能知道数据都是有序的,所以单调栈分为单调递增单调递减。
现在有一组数,10 3 7 4 12从左往右以此进行入栈,如果栈空或者入栈元素值小于栈顶元素,那么入栈;否则,入栈就会破坏单调性,需要把比入栈元素小的元素全部出栈,递减栈就反过来。

  1. 10入栈,栈为空,直接入栈
  2. 3入栈时,栈顶元素10大于3,入栈
  3. 7入栈,栈顶元素3比7要小,所以3出栈7入栈
  4. 4入栈,栈顶元素7大于4入栈
  5. 12入栈是,元素10 7 4全部小于12,全部出栈
    单调栈的时间复杂度是线性的,O(n)
int dandiao()
{
	for(int i=1; i<=n; i++) {
		if(s.empty()||a[i]<=a[s.top()]) s.push(i);//存储编号
		else {
			while(s.size()&&a[i]>a[s.top()]) {
				answer[s.top()]=i;
				s.pop();
			}
			s.push(i);
		}

	}
	for(int i=1; i<=n; i++)
		printf("%d ",answer[i]);
}

单调队列

单调队列能解决一个叫滑动窗口的问题
问题是这样的,给定一个长度为n的整数序列,从中找出一段长度不超过m的子序列,使得子序列里面的数最大(学完动态规划,会发现,这就和求LIS差不多,所以才有一种方法叫做单调队列优化)
这种问题看上去很像有个不固定的窗口在移动,所以叫做滑动窗口问题
计算区间和这种问题,一般转化为前缀和进行加减的问题进行求解,我们求出si表示前i项的和,那么子序列l~r之间的和就等于sr-sl
所以我们就可以把问题转化为找两个点x,y,使sx-sy最大
这个策略说明“下标递增,前缀和递减”我们对i进行如下操作
1.判断对头的i的距离是否超出m,超出出队
2.否则此时对头是i时,j就是最佳的选择
3.不断删除队尾大的决策,知道队尾的s小于si,然后把i作为一个决策入队
单调队列的时间复杂度也是线性的O(n)

int l=1,r=1;//队头队尾 
q[1]=0;
for(int i=1;i<=n;i++)
{
	while(l<=r&&q[l]<i-m) l++;//控制窗口
	ans=max(ans,sum[i]-sum[q[l]]);
	while(l<=r&&sum[q[r]]>=sum[i]) r--;//接着找答案
	//把比我小的全部出队,说明不可能是最大的 
	q[++r]=i;//这个答案有可能  
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值