力扣1944.队列中可以看到的人数--单调栈

思路:

  • 由题知一个人能 看到 他右边另一个人的条件是这两人之间的所有人都比他们两人 矮 ,也就是说,在自己右边第一个比自己高的人后面的人就肯定看不到了

  • 那么只需要找到右边第一个比自己高的人与自己之间的所有满足要求的人就行了,怎么找?一个个判断中间是否有不满足要求的人吗?可行,但太慢。通过分析,不难发现在此区间内满足要求的人身高呈递增增长,也就是说,只要左边有比自己高的人那么这个人肯定看不到:

  • 那么只需要判断指定范围内每有一个满足条件的人就将能看到人数加一就行了
    代码:

    复制代码
    class Solution {
    public:
        vector<int> canSeePersonsCount(vector<int>& heights) {
            int len = heights.size();
            vector<int> answer(len);    //记录每个人可以看到几个人
    
            for(int i = 0; i < len - 1; i++){   //遍历除最后一个人外的每一个人,因为最后一个人能见人数肯定是0
                if(heights[i + 1] >= heights[i]){answer[i] = 1;continue;}   //如果右边第一个人就比自己高,直接记为1,跳过此次循环
                answer[i] = 1;   //记录当前人可见人数,因为已经判断右边第一个人,所以初值为1
                int t = heights[i + 1]; //记录左边的最高人,初值为当前人右边的人
    
                for(int j = i + 2; j < len; j++){   //从当前人右边第二个开始判断是否可见
                     if(heights[j] >= heights[i]){answer[i]++;break;}    //遇到比当前人更高的人,记录,并退出遍历
                     if(heights[j] < t) continue;    //如果左边有比自己更高的人,则跳过
                     t = heights[j];    //如果没有,则自己为当前最高的,更换最高人
                     answer[i]++;    //记录,能到这里,说明满足条件
                }
    
            }
    
            return answer;
        }
    };
  • 这个方法是我一开始的想法,没有问题,但是......

  • 真狠啊

  • 显然O(n^2)是不行了,那么就得想一个更快的方法。通过分析,不难发现在之前的方法里可以优化的点是:对于某个人,只要他左边有一个比他更高的人,那么在那个比他更高的人之前的所有人都看不到他

  • 也就是说,对于某个值,只要把能看到他的人都记录完,此时他就不被需要了可以忽视了,也就是说可以使用一个栈将每个值记录,对于不再被需要的值就弹出,在弹出的过程中刚好记录可见人数,同时将维护单调栈,从栈底到栈顶,身高严格递减

    复制代码
    假设输入为heights = [10,6,8,5,11,9],对于这个输入——

    |---|--------|------------|------------|------|---------------|
    | i | hi | 入栈前 | 入栈后 | 可见人数 | 解释 |
    | 5 | 9 | \[\] | 9 | 0 | |
    | 4 | 11 | 9 | 11 | 1 | 11挡住9,弹出9 |
    | 3 | 5 | 11 | 11,5 | 1 | |
    | 2 | 8 | 11,5 | 11,8 | 2 | 8挡住5,弹出5 |
    | 1 | 6 | 11,8 | 11,8,6 | 1 | |
    | 0 | 10 | 11,8,6 | 11,10 | 3 | 10挡住8,6,弹出8,6 |

代码:

复制代码
class Solution {
public:
    vector<int> canSeePersonsCount(vector<int>& heights) {
        int len = heights.size();
        stack<int> stack;   //栈
        vector<int> answer(len);    //记录可见人数

        for(int i = len - 1; i >= 0; i--){  //从最后一个开始压栈
            while(!stack.empty() && stack.top() < heights[i]){  //如果栈不为空且栈顶元素小于当前要压栈元素
                stack.pop();    //弹栈
                answer[i]++;    //记录
            }

            if(!stack.empty()) answer[i]++; //若栈不为空,则代表当前要压栈元素后边还有一个比之更高的人可见,记录

            stack.push(heights[i]);     //压栈
        }

        return answer;
    }
};
相关推荐
Raink老师21 小时前
【AI面试临阵磨枪-79】实时数据 RAG:订单、商家、物流、天气、动态库存
人工智能·面试·职场和发展
MC皮蛋侠客21 小时前
Google Test 单元测试指南
c++·单元测试·google test
Cosolar21 小时前
Chroma向量库面试学习指南
数据库·人工智能·面试·职场和发展·数据库架构
艾莉丝努力练剑1 天前
【Linux:文件】Ext系列文件系统进阶
linux·运维·服务器·c++·文件系统·文件io·ext
kkeeper~1 天前
0基础C语言积跬步之数据在内存中的存储
c语言·数据结构·算法
wabs6661 天前
关于贪心算法的一些自我总结【力扣45.跳跃游戏II】【灵感来源:代码随想录】
算法·贪心算法·复盘
2401_876964131 天前
【湖北专升本】2026湖北专升本真题PDF+备考资料汇总
数据结构·人工智能·经验分享·深度学习·算法·计算机视觉
basketball6161 天前
C++ NULL 和 nullptr 区别 以及 nullptr 的核心实现
java·开发语言·c++
嗝o゚1 天前
CANN GE 算子融合——融合算法与调度策略
算法·昇腾·cann·ge
小江的记录本1 天前
【JVM虚拟机】垃圾回收GC:垃圾回收算法:标记-清除、标记-复制、标记-整理、分代收集(附《思维导图》+《面试高频考点清单》)
java·jvm·后端·python·算法·安全·面试