【单调栈】

单调栈

1.0 原始模型

描述:给定一个序列,求出序列每个位置在左侧距离其最近的,且比起小的数,如果不存在则返回-1,存在则返回其值, 最后输出该结果。
解析:
	首先考虑对该题目的朴素解(暴力解法),挖掘一些性质,把求解空间进一步缩小,从而降低问题的求解时间复杂度。
	1. 暴力做法
	双重循环:第一重循环,遍历序列上所有的位置i;
	        第二重循环,从第一重循环的位置i开始,向左遍历,直到找到第一个比位置i处的值,否则输出-1,表示不存在这样的小值;
	        伪码如下:
	        for i = 0; i < n; i++
	        	for j = i- 1; j >= 0; j--
	        		if (a[i] > a[j]) {
	        			cout << a[j] <<endl;
	        			break;
	        		} 
	        	cout << -1 << endl;
	2.分析特性
	    可以观察,当我们通过一些数据结构,可以保留之前遍历过的所有的元素,对于给定位置i, 那么假设在i的左侧存在两个位置j,k,满足
	    a[j] >= a[k] (j < k),因为是需要找左侧最近,所以这时选择k位置比j位置更优,对于位置i,位置k更优,因此可以舍去位置j。
	    因为上面实际上是逆序的情况,要删除这种逆序情况,这样得到的序列是严格递增的。因为我们在比较时,总是要比较左侧最近的点,因此需要使用栈的数据结构来
	    使用。
	3.代码实现
	stack st;
	int a[N];
	
	for (int i = 0; i < n; i++)
	{
		//对于位置i,需要考察期左侧的栈序列;
		while (!st.empty() && st.top() >= a[i]) 
		{  //栈非空,且比栈顶元素小,说明其可以取代栈顶成为更优解;
			st.pop();
		}
		
		//此处要么栈为空,或者当前元素比栈顶大;
		if (!st.empty()) 
		{
			//此时栈非空,那么栈顶就是其左侧比当前值还小的元素;
			cout << st.top() << endl;
		} else {
			//栈为空,说明左侧没有符合的值了,这个时候输出特殊情况处理;
			cout << -1 <<endl;
		}
		//将当前元素添加进去,因为在当前元素之前已经保持了严格递增,将当前元素添加进去后,单调性还是保持不变
		//因为前面的if语句已经保证了,从而可以保证该性质可以求解。
		st.push(a[i]);
	}
#include <iostream>
#include <algorithm>

using namespace std;
const int N = 100010;
//这里采用的是数组模拟栈的方式,完全可用STL的方式来写,只不过会增加一些运行时间;
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 <<endl;
    return 0;
    
}

1.1 扩展

类似的,还有寻找左侧最近且最大的,右侧最近最小/最大的问题。

2.0参考

  1. https://www.acwing.com/video/258/
posted @   zhanghanLeo  阅读(69)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示