单调栈
本文不介绍栈,以及栈的基本操作。对栈不熟悉的读者可以先熟悉一下栈再了解单调栈。
单调栈故名思意,栈中元素全部都是递增(递减)的,维护栈需要保持这种性质。
用途:解决Next Greater(Lesser) NUmber
举例:
给你一个数组A [2,1,2,4,3],你返回数组B [4,2,4,-1,-1] (解释:数组保存下一个更大元素下标)。
假设三个元素位置为i,j,k且满足k>j>i。
这时候j,k可能是i的下一个元素有两种情况。
- A[j]<A[k]
这种情况下A[j],A[k]都可能是下一个更大元素。 - A[j]>A[k]
这种情况只用可能A[k]是解,因为A[j]比A[k]大不可能找到k的位置。
思路:
- 维护一个数据结构,遇到2情况抛弃A[k],1则保留A[j]和A[k]。这时候你就发现这个数据结构中的元素是单调的。
- 假设我们遍历到元素1,此时我们保留有[2,4]。因为我们需要找的是下一个较大元素,所以应该从2这个方向开始(和存入反向相反)---->栈的特性
综上:使用栈维护一个单调增序列
算法模板
vector<int> nextGreaterElement(vector<int>& nums) {
vector<int> ans(nums.size()); // 存放答案的数组
stack<int> s;
for (int i = nums.size() - 1; i >= 0; i--) { // 后向前遍历
while (!s.empty() && s.top() <= nums[i]) { // 是否满足递增要求
s.pop();
}
ans[i] = s.empty() ? -1 : s.top(); // 栈顶元素/最大值
s.push(nums[i]); // 找到合适位置入栈
}
return ans;
}
思路扩展
Tips:这个例子中栈中存储的是元素值,但其实存储元素的下标会更有可扩展性。因为既可以通过下标访问到元素的值,同时还可以进行的下标的运算(下一个最大元素距离–下标做差)。
扩展题目
上面这个题目中1. 2.两种情况都是保持一个单调性。但在有些题目中2.情况下的A[k]也会有用途而不是单纯被移除。
举例:
132 模式:
nums = [3,1,4,2 ] 数组。三个元素下标 i < j < k 和且nums[i] < nums[k] < nums[j]。
如果 nums 中存在 132 模式的子序列 ,返回 true ;否则,返回 false 。
思路:同理我们还是维护一个单调增栈,但出栈的元素需要记录下来,同时维护出栈的最大值max。然后满足max>stack.top()即可。
单调栈–> 满足13条件 32条件
记录max–>满足 12条件