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 个人在他右侧队列中能 看到 的 人数 。

 实例

示例 1:

 

输入:heights = [10,6,8,5,11,9]
输出:[3,1,2,1,1,0]
解释:
第 0 个人能看到编号为 1 ,2 和 4 的人。
第 1 个人能看到编号为 2 的人。
第 2 个人能看到编号为 3 和 4 的人。
第 3 个人能看到编号为 4 的人。
第 4 个人能看到编号为 5 的人。
第 5 个人谁也看不到因为他右边没人。
示例 2:

输入:heights = [5,1,2,3,10]
输出:[4,1,1,1,0]

提示:

n == heights.length
1 <= n <= 105
1 <= heights[i] <= 105
heights 中所有数 互不相同 。

题解

我们可以使用一个单调递减的栈,从栈底到栈顶逆序地存储当前可能可以被看见的人的下标。同时,这些下标的 heights 值也是单调递减的。

我们逆序遍历这 n 个人的下标,如果当前遍历到了第 i 个人,那么我们需要在栈中选出第 i 个人可以看到的那些人。设栈顶的下标为 j,则:

如果栈为空,说明第 i 个人是遍历到的所有人中最高的那个人,我们退出比较环节;

如果 height[i]>height[j],说明 i 能够看到 j,并且根据提示 2,i 左侧的所有人都无法看到 j,因此我们将 j 出栈,并继续将 i 与新的栈顶元素进行比较;

如果 height[i]<height[j],说明 i 能够看到 j,但是根据提示 2,i 无法看到 j 右侧的所有人,因此我们退出比较环节。

在比较结束后,栈要么为空,要么其栈顶下标 j 满足 height[i]<height[j]。我们将 i 入栈,就可以保持其单调性。

这个题就是使用一个单调递减的栈,在遍历一个h[i]的时候,把比h[i]小的都出栈,然后这个h[i]的答案就是出栈的个数+现在栈中还有没有元素。

这个为啥能用单调栈呢,假设来了一个元素,那么栈中比他小的元素,对后面一定是没有影响的

代码

class Solution {
public:
    vector<int> canSeePersonsCount(vector<int>& h) {
        stack<int>s;
        int len=h.size();
        vector<int>ans(len);
        for(int i=len-1;i>=0;i--){
            while(s.size()&&h[i]>s.top()){
                ans[i]++;
                s.pop();
            }
            if(s.size()) ans[i]++;
            s.push(h[i]);
        }
        return ans;
    }
};

 

posted @ 2021-07-28 23:14  lipu123  阅读(100)  评论(0)    收藏  举报