当前位置: 首页 > news >正文

单调栈的“视线”魔法:统计「队列中可以看到的人数」

哈喽各位,我是前端小L。

我们的单调栈工具箱,已经能熟练处理“下一个/上一个 更大/更小”元素了。这些问题大多是寻找一个单一的目标。今天,我们的挑战升级了:我们要从一个“寻找者”变成一个“统计者”。

这道题是对单调栈“清算”逻辑的一次绝佳应用。我们将从右向左遍历,维护一个“天际线”,并巧妙地在 while 循环和 if 判断中,完成“能看到的所有矮个子”+“那个挡住你的高个子”的精妙计数。

力扣 1944. 队列中可以看到的人数

https://leetcode.cn/problems/number-of-people-visible-in-a-queue/

题目分析:

  • 输入:一个身高数组 heights,代表一群人从左到右站成一排。

  • 规则:你站在队列中(假设是 i 位置),看向右边。你能看到 jj > i),当且仅当 ij 之间的所有人,都比你俩矮。

    • 规则的简化版:i 能看到 j,当且仅当 min(heights[i], heights[j]) > max(heights[k] for k in (i+1, j-1))

  • 目标:返回一个数组 ansans[i] 表示第 i 个人能看到右边多少人。

例子: heights = [10, 6, 8, 5, 11, 9]

  • i=0 (10): 能看 6 (min(10,6)>max(empty)), 能看 8 (min(10,8)>max(6)), 不能看 5 (min(10,5)<max(6,8)), 能看 11 (min(10,11)>max(6,8,5)), 但 11 会挡住 9。共 3 人。

  • i=1 (6): 能看 8 (min(6,8)>max(empty)), 但 8 会挡住 5, 11 也比 6 高,但被 8 挡住了。共 1 人。

  • i=2 (8): 能看 5 (min(8,5)>max(empty)), 能看 11 (min(8,11)>max(5)), 但 11 会挡住 9。共 2 人。

  • i=3 (5): 能看 11 (min(5,11)>max(empty)), 但 11 会挡住 9。共 1 人。

  • i=4 (11): 能看 9 (min(11,9)>max(empty)). 共 1 人。

  • i=5 (9): 右边没人。共 0 人。

最终答案: [3, 1, 2, 1, 1, 0]

思路一:朴素的“视线检查” (O(n²))

最直观的方法,就是模拟这个过程:

  1. 遍历每个人 i

  2. 再遍历 i 右边的每个人 j

  3. (i, j) 之间,维护一个 current_max_height

  4. 如果 min(heights[i], heights[j]) > current_max_height,说明 i 能看到 jcount++

  5. current_max_height = max(current_max_height, heights[j]) (不对,应该是 heights[j-1]?)。

这个逻辑很绕,很容易出错,而且时间复杂度至少是 O(n²)。我们需要更清晰的 O(n) 解法。

“Aha!”时刻:从右向左,维护“天际线”

这个“视线”问题,如果从左向右看,会非常复杂。但如果我们从右向左遍历,问题会变得异常简单。

我们维护一个单调递减的栈。这个栈代表了从“我”右边看过去的“天际线”。

算法流程:

  1. 初始化一个空栈 s(存储索引)和一个结果数组 ans(长度 n,初始全为0)。

  2. 从右向左遍历数组 ( in-10 ): a. 初始化当前人 i 的可见人数 count = 0。 b. “清算矮个子” (while 循环)while (!s.empty() && heights[i] > heights[s.top()]) * 当前的 i 比栈顶的人 s.top() 要高。 * i 的视线可以“越过”s.top(),所以 i 肯定能看到 s.top()。 * count++。 * s.pop() (这个“矮个子”被 i 看到了,并且他不会阻挡 i 看更远,所以弹出)。 c. “遇到高墙” (if 判断): * while 循环结束时,栈顶(如果存在)的人 s.top(),必然大于或等于 heights[i]。 * i 的视线到这里就被挡住了。 * 但是,i 能看到这个“高墙”本身! * if (!s.empty()) { count++; } d. “加入天际线” (push): * 将当前人 i索引压入栈。他将成为左边的人(i-1)眼中的“天际线”的一部分。 * s.push(i); e. 记录答案ans[i] = count;

  3. 返回 ans

代码实现 (单调递减栈)

#include <vector>
#include <stack>using namespace std;class Solution {
public:vector<int> canSeePersonsCount(vector<int>& heights) {int n = heights.size();vector<int> ans(n, 0);stack<int> s; // 存储索引的单调递减栈// 从右向左遍历for (int i = n - 1; i >= 0; --i) {int count = 0;// 1. 清算所有比我矮的(我能越过他们看)// 栈保持单调递减while (!s.empty() && heights[i] > heights[s.top()]) {count++; // 我能看到这个比我矮的s.pop();}// 2. 遇到第一个比我高(或等高)的“高墙”if (!s.empty()) {count++; // 我能看到这个“高墙”}// 3. 将我加入“天际线”s.push(i);// 4. 记录答案ans[i] = count;}return ans;}
};

复杂度分析

  • 时间复杂度 O(n): 我们只从右向左遍历了数组一次。while 循环中的 poppush 操作是关键。每个元素的索引 i 最多只入栈一次、出栈一次。因此,所有栈操作的总和是 O(n)(摊销分析)。总时间复杂度是 O(n)。

  • 空间复杂度 O(n): 在最坏的情况下,例如一个严格递减的数组 [5, 4, 3, 2, 1]while 循环永远不会执行,所有元素的索引都会被压入栈中。此时栈的空间占用为 O(n)。

总结:单调栈的“计数”模式

今天这道题,再次展现了单调栈在处理“视线”和“边界”问题上的强大能力。它和 LC 901(股票跨度)有异曲同工之妙,但又有所不同:

  • LC 901 (向左看)while(price >= top.price)span += top.span。它在“吸收”矮个子的跨度

  • LC 1944 (向右看)while(height > top.height)count++。它在“清点”矮个子的数量

这两个问题,都利用了单调栈(一个递增,一个递减)来高效地跳过那些“无关紧要”的中间元素,并在 O(n) 时间内完成了复杂的统计。

下期见!

http://www.dtcms.com/a/568857.html

相关文章:

  • 【2025 SWPU-NSSCTF 秋季训练赛】WebFTP
  • 海淀教育互动平台网站建设哪些网站是wordpress
  • 网站开发定制宣传图片北京百度推广排名优化
  • ELK企业级日志分析系统学习
  • 360开源FG-CLIP2,给人工智能升级了精准的视觉解析系统
  • 关于dify中http节点下载文件时,文件名不为原始文件名问题解决
  • 期中考试成绩查询系统制作方法
  • Vue 用户管理系统(路由相关练习)
  • AI时代的新SEO玩法:使用SERP API构建排名追踪系统
  • 宝塔配置:IP文件配置,根据端口配置多个项目文件(不配置域名的情况)
  • 网站布局怎么设计哪个网站可以学做蛋糕
  • 深圳网站设计兴田德润信任高网站推广目标是什么
  • Java并发List实战:CopyOnWriteArrayList原理与ArrayList常见面试题
  • 【JavaEE】-- Cookie Session
  • --- Http和Https协议 ---
  • 无HTTP服务时的文件传输方法大全
  • 微信注册重庆网站优化方式
  • Spring Boot Web上下文工具类详解:获取Request、Response和参数
  • php购物网站开发实例源码杭州小程序制作公司排行榜
  • 测试开发话题09---自动化测试常用函数(1)
  • Linux - Fail2ban搭配 firewallcmd-rich-rules 完整部署教程
  • 使用 nvm 安装 Node.js
  • Arbess零基础学习 - 使用Arbess+GitLab实现Node.js项目自动化构建/主机部署
  • Linux 虚拟化技术 KVM/ESXI/Docker
  • C006基于博途西门子1200PLC机械手分拣物料控制系统仿真
  • 网站建设ui设计dw怎么做别人可以看的网站
  • 毕业生就业网站开发项目禁用wordpress默认编辑器
  • 服务器数据恢复—raid5阵列硬盘离线搞崩溃,分区数据恢复案例来袭
  • 基于springboot的新闻资讯系统
  • H3C AC+AP本地转发二层组网