C++数据结构之单调栈

定义

单调栈(Monotone Stack):一种特殊的栈。在栈的「先进后出」规则基础上,要求「从 栈顶栈底 的元素是单调递增(或者单调递减)」。其中满足从栈顶到栈底的元素是单调递增的栈,叫做「单调递增栈」。满足从栈顶到栈底的元素是单调递减的栈,叫做「单调递减栈」。

这里是以栈顶到栈底的顺序为基准来描述单调栈。

1. 基础

1.1单调递增栈

单调递增栈:只有比栈顶元素小的元素才能直接进栈,否则需要先将栈中比当前元素小的元素出栈,再将当前元素入栈。

这样就保证了:栈中保留的都是比当前入栈元素大的值,并且从栈顶到栈底的元素值是单调递增的。

经常出现的考题如下,模拟数组[2, 7, 5, 4, 6, 3, 4, 2]在单调递增栈的进栈、出栈过程。

第 i 步 待插入元素 操 作 结 果(左侧为栈底) 作 用
1 2 2 入栈 [2] 元素 2 的左侧无比 2 大的元素
2 7 2 出栈,7 入栈 [7] 元素 7 的左侧无比 7 大的元素
3 5 5 入栈 [7, 5] 元素 5 的左侧第一个比 5 大的元素为:7
4 4 4 入栈 [7, 5, 4] 元素 4 的左侧第一个比 4 大的元素为:5
5 6 4 出栈,5 出栈,6 入栈 [7, 6] 元素 6 的左侧第一个比 6 大的元素为:7
6 3 3 入栈 [7, 6, 3] 元素 3 的左侧第一个比 3 大的元素为:6
7 4 3 出栈,4 入栈 [7, 6, 4] 元素 4 的左侧第一个比 4 大的元素为:6
8 2 2 入栈 [7, 6, 4, 2] 元素 2 的左侧第一个比 2 大的元素为:4

1.2 单调递减栈

单调递减栈:只有比栈顶元素大的元素才能直接进栈,否则需要先将栈中比当前元素大的元素出栈,再将当前元素入栈。

这样就保证了:栈中保留的都是比当前入栈元素小的值,并且从栈顶到栈底的元素值是单调递减的。

这里同样以[4, 3, 2, 5, 7, 4, 6, 8]为例

第 i 步 待插入元素 操 作 结 果(左侧为栈底) 作用
1 4 4 入栈 [4] 元素 4 的左侧无比 4 小的元素
2 3 4 出栈,3 入栈 [3] 元素 3 的左侧无比 3 小的元素
3 2 3 出栈,2 入栈 [2] 元素 2 的左侧无比 2 小的元素
4 5 5 入栈 [2, 5] 元素 5 的左侧第一个比 5 小的元素是:2
5 7 7 入栈 [2, 5, 7] 元素 7 的左侧第一个比 7 小的元素是:5
6 4 7 出栈,5 出栈,4 入栈 [2, 4] 元素 4 的左侧第一个比 4 小的元素是:2
7 6 6 入栈 [2, 4, 6] 元素 6 的左侧第一个比 6 小的元素是:4
8 8 8 入栈 [2, 4, 6, 8] 元素 8 的左侧第一个比 8 小的元素是:6

单调栈的适用场景

单调栈可以在时间复杂度为 O(n) 的情况下,求解出某个元素左边或者右边第一个比它大或者小的元素。

所以单调栈一般用于解决一下几种问题:

  • 寻找左侧第一个比当前元素大的元素。
  • 寻找左侧第一个比当前元素小的元素。
  • 寻找右侧第一个比当前元素大的元素。
  • 寻找右侧第一个比当前元素小的元素。

上边的分类解法有点绕口,可以简单记为以下条规则:

  • 无论哪种题型,都建议从左到右遍历元素。
  • 查找 「比当前元素大的元素」 就用 单调递增栈,查找 「比当前元素小的元素」 就用 单调递减栈
  • 「左侧」 查找就看 「插入栈」 时的栈顶元素,从 「右侧」 查找就看 「弹出栈」 时即将插入的元素。

单调栈模板

单调递增栈

//单调递增栈
template<typename T>
void IncStack(stack<T>& s,const vector<T> &nums) {
    
    
	for (auto it = nums.begin(); it != nums.end(); it++) {
    
    
		while (!s.empty() && s.top() <= *it) {
    
    
			s.pop();
		}
		s.push(*it);
	}
}

这个模板是将数组转化成单调递增栈。

单调递减栈

//单调递减栈
template<typename T>
void DecStack(stack<T>& s, const vector<T>& nums) {
    
    
	for (auto it = nums.begin(); it != nums.end(); it++) {
    
    
		while (!s.empty() && s.top() >= *it) {
    
    
			s.pop();
		}
		s.push(*it);
	}
}

老规矩,有用二连,感谢大家!

猜你喜欢

转载自blog.csdn.net/suren_jun/article/details/127446815