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

【队列】----【Keep In Line】

题目描述

又到饭点了,SK 同学靠着惯性走到了食堂,但长长的队伍顿时让他失去了食欲。突然,他注意到某个窗口前的队伍里明显存在插队的现象,于是他默默记录下了同学们进队和出队的变化。

  • 对于进队,SK 同学只知道队伍里多了一个人,并不知道新来的人是老老实实站到了队尾还是插到了队伍里的某个位置;
  • 对于出队,SK 同学能确定是队伍里站在最前面的人出队了。

初始时队伍为空。

给出 n n n 条队伍进出的信息,保证已经出队的同学不会再入队,并且最终队伍也为空,SK 同学想知道有多少不插队的好同学。


输入描述

  • 第一行是一个正整数 T ( 1 ≤ T ≤ 5 ) T \ (1 \leq T \leq 5) T (1T5),表示测试数据的组数。
  • 对于每组测试数据:
    • 第一行是一个整数 n ( 1 ≤ n ≤ 1 0 5 ) n \ (1 \leq n \leq 10^5) n (1n105),表示这个队伍进出的信息数。
    • 接下来 n n n 行,每行为两个字符串 OptName
      • Opt"in" 表示进队;
      • Opt"out" 表示出队;
      • Name 为进队或出队的人的名字,长度不超过 10;
      • 保证所有人的名字各不相同;
      • 所有操作按时间顺序给出;
      • 最终队列为空。

输出描述

对于每组测试数据,输出一行,包含一个整数,表示不插队的好同学人数


示例1

输入
1
6
in quailty
in hwq1352249
out hwq1352249
in zhuaiballl
out quailty
out zhuaiballl
输出
2

题解:(模拟 + 贪心 + 哈希 + 有序集合)

一、问题抽象

队列是一个先进先出(FIFO)的结构:

  • 入队:我们无法判断这个人是否站在了队尾;
  • 出队:我们可以确定队首的人离队;
  • 因此,只有在出队时才能判断是否插队

我们对每个进入队伍的人打上一个时间戳(即第几个入队),就能通过时间顺序来判定插队行为:

  • 如果一个人出队时,他不是当前入队最早尚未出队的人 ⇒ 插队;
  • 否则,他是好同学。

二、解题思路

1. 数据结构设计

  • unordered_map<string, int> 存储每个人的入队时间戳;
  • unordered_map<string, bool> 存储每个人是否“未插队”;
  • set<int> 存储当前仍在队中的人的时间戳集合(自动排序);

2. 时间戳分配

我们定义一个变量 one,每当一个人入队时,递增分配一个时间戳,保证入队顺序唯一。

3. 插队判定逻辑

当一个人出队时:

  • 查看当前队伍中最早的时间戳 min_timestamp
  • 如果该人的时间戳比 min_timestamp 大 ⇒ 他比最早入队的人还早出队 ⇒ 插队;
  • 否则,没插队。

无论是否插队,都要从当前队伍集合中删去该人的时间戳,表示其出队。


三、样例说明

输入:

1
6
in quailty
in hwq1352249
out hwq1352249
in zhuaiballl
out quailty
out zhuaiballl

处理过程:

  1. quailty 入队(时间戳 1);
  2. hwq1352249 入队(时间戳 2);
  3. hwq1352249 出队,但 quailty(时间戳 1)还没出 ⇒ 插队;
  4. zhuaiballl 入队(时间戳 3);
  5. quailty 出队(正常);
  6. zhuaiballl 出队(正常);

最终只有 quailty、zhuaiballl 是好同学,输出 2


四、完整代码:

#include <bits/stdc++.h>
using namespace std;// 定义 int 为 long long,避免 int 范围不够(尤其是时间戳可能很大)
#define int long longsigned main()
{// 读入测试组数int t;cin >> t;// 逐组处理while (t--){int n;cin >> n; // 读入本组中操作的总条数string a, b;// 记录每个人的入队时间戳(越早入队,时间戳越小)unordered_map<string, int> times;// 记录每个人是否是“好同学”(未插队),默认 true,若判定插队则置为 falseunordered_map<string, bool> bools;// 记录当前在队伍中的所有人(通过他们的时间戳),用 set 自动维护升序set<int> time;// 全局时间戳计数器,每次“in”操作时递增,给入队者分配时间戳int one = 0;// 处理 n 条操作while (n--){cin >> a >> b; // a 是操作类型(in/out),b 是人名if (a == "in"){// 入队操作one++;                    // 分配一个新的时间戳times[b] = one;          // 记录该人的时间戳bools[b] = true;         // 初始认为该人是“好同学”time.insert(one);        // 将时间戳加入当前队列(表示他在队中)}else if (a == "out"){// 出队操作:只能从队首出队(即当前 time 中最小时间戳)auto it = time.begin();         // 队首对应的最小时间戳if (times[b] > (*it)){// 如果当前出队者的时间戳比队首还大// 说明他不是队伍里最早的人 => 插队了bools[b] = false;}// 无论是否插队,该人已出队,从集合中删除他的时间戳time.erase(times[b]);}}// 最终统计未插队的“好同学”人数int ans = 0;for (auto p : bools){if (p.second == true){ans++;}}// 输出本组的答案cout << ans << endl;}return 0;
}

五、时间复杂度分析

操作复杂度
每条 in / out 操作 O ( l o g n ) O(log n) O(logn)(主要是 set 的插入/删除)
总体(每组测试) O ( n l o g n ) O(n log n) O(nlogn)
总体(所有测试组) O ( T ∗ n l o g n ) O(T * n log n) O(Tnlogn),T ≤ 5,n ≤ 1e5

六、总结

  • 本题核心思想是用时间戳记录顺序,再借助 set 维护在队人中谁是最早入队的;
  • 插队与否只在出队时判定,通过时间戳与当前队首的比较;
  • 是一道典型的模拟 + 贪心判断 + 哈希 + 有序集合混合使用的好题,体现了实际调度逻辑模拟能力。

相关文章:

  • 阶段二开始-第一章—8天Python从入门到精通【itheima】-116节(封装)
  • 国防科大刘丽教授团队提出了一种用于合成孔径雷达目标识别的解耦自监督子空间分类器|TGRS
  • C++11新库特性:从入门到精通
  • 《Opto-Electronic Advances》热点论文速览(2025)
  • 【Python】实现对LGBT+ rights worldwide (2025)数据集的可视化展示
  • react + ant-design实现数字对比动画效果:当新获取的数字比之前展示的数字多或少2时,显示“+2”或“-2”的动画效果
  • A模块 系统与网络安全 第三门课 网络通信原理-2
  • 《二分枚举答案(最值问题)》题集
  • 3.web逆向之开发者工具调试
  • Spring Cloud 微服务(服务注册与发现原理深度解析)
  • VUE使用过程中的碰到问题记录
  • 听觉节律如何重塑α波?FREQ-NESS解密大脑动态重构
  • 查看SAP ERP系统各个版本号的方法:ECC、S/4HANA、Business One
  • AI+预测3D新模型百十个定位预测+胆码预测+去和尾2025年6月27日第121弹
  • SOME/IP 和 DDS 的详细对比,内容涵盖它们的核心差异、适用场景及选型建议
  • 北斗电动车定位器:守护出行安全的实用工具
  • 深入学习MySQL的页分裂(Page Split)
  • 学习接口自动化框架pytest有哪些好处?
  • 还在手动部署?用Jenkins+Docker+Git实现自动化CI/CD
  • 助力高考,利用python获取本专科专业选考科目要求