什么时候使用单调栈
单调栈能很好的对一组元素的峰、谷进行筛选处理,遇到和峰谷相关的场景,可以考虑用单调栈算法。
单调栈使用中思路和注意实现:
- 确认方向(左->右? 右->左?)
- 确认栈类型(递增/递减单调栈)
- 递增单调栈:大数为出栈触发点,小数出栈;最终栈内数据一定包含最大那个数。
- 递减单调栈:小数为出栈触发点,大数出栈;最终栈内数据一定包含最小那个数
- 业务目标结果与栈的关系(与出栈元素
有关 ;与栈内残余数据有关)
- 业务与逐个元素有关,一般选择与出栈元素有关。(如:矩形面积、接雨水)
- 业务与序列最大/小元素有关,一般选择与残余数据关联。(如滑窗内最大值)
- 业务是与出栈数据/残余数据有关,数据找大/找小,决定了使用递增/递减单调栈。
遇到单调栈解决问题的业务场景,先根据单调栈特点建业务模型:
业务和单调栈关联模型:注意
- 选择关联合适的触发出栈点index、出栈元素index、出栈前、后元素index。
- 如有需要,可以入栈时调整index、原始数据。(如:计算矩形面积案例)
相等元素处理策略:触发出栈处理、还是入栈处理。
残余数据处理策略:根据不同业务,考虑最终栈内残余单向元素是否需要出栈处理。
参考链接:
链接: 【算法】单调栈
题目:1944.队列中可以看到的人数
有 n 个人排成一个队列,从左到右 编号为 0 到 n - 1 。给你以一个整数数组 heights ,每个整数 互不相同,heights[i] 表示第 i 个人的高度。
一个人能 看到 他右边另一个人的条件是这两人之间的所有人都比他们两人 矮 。更正式的,第 i 个人能看到第 j 个人的条件是 i < j 且 min(heights[i], heights[j]) > max(heights[i+1], heights[i+2], …, heights[j-1]) 。
请你返回一个长度为 n 的数组 answer ,其中 answer[i] 是第 i 个人在他右侧队列中能 看到 的 人数 。
思路:对某个人来说,如果此人的右边都是更矮的,那么对此人的左边,最多只能看到此人,因为此人的右边都被挡住了
具体方法:从右往左遍历数组,与栈顶进行比较,若大于栈顶则一直弹出直到空或小于,再将遍历的数组元素放入栈中,中间弹出的元素即为右侧能看到的元素。
代码:
class Solution {
public:
vector<int> canSeePersonsCount(vector<int>& heights) {
stack<int> temp;
int n=heights.size();
vector<int> result(n,0);
for(int i=n-1;i>=0;i--){
while(!temp.empty()&&temp.top()<heights[i]){
result[i]++;
temp.pop();
}
//栈不为空时,栈顶的元素比遍历到的大,可看到栈顶
if(!temp.empty()){
result[i]++;
}
temp.push(heights[i]);
}
return result;
}
};