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

统计出哪个时间段在线人数最多

要统计出哪个时间段在线人数最多,这是一个经典的区间重叠问题,通常使用“扫描线算法”(Sweep Line Algorithm)来解决。算法的核心思想是将用户的登录和登出时间视为事件(登录事件增加在线人数,登出事件减少在线人数),然后按时间顺序扫描这些事件,同时维护一个在线人数计数器,并记录人数达到峰值的时间段。

以下是详细的解决步骤,包括算法描述和伪代码(以 Python 为例)。假设输入是用户登录和登出时间的列表,每个用户有一个登录时间(start)和登出时间(end),时间格式可以是整数(如时间戳)或字符串(如 "HH:MM"),但在处理前需统一转换为可排序的格式(如整数分钟或时间对象)。
算法步骤
事件处理:

为每个用户创建两个事件:

登录事件:(start_time, +1),表示在线人数增加。

登出事件:(end_time, -1),表示在线人数减少。

将所有事件放入一个列表中。

事件排序:

按时间升序排序事件列表。

关键点:如果同一时间有多个事件,需指定处理顺序。通常,先处理登出事件(-1),再处理登录事件(+1),以避免瞬时计数错误(例如,同一时间登出和登录时,登出应先处理,确保计数合理)。排序规则:时间相同时,-1 事件排在 +1 事件之前。

扫描事件并统计:

初始化:

count = 0:当前在线人数。

max_count = 0:最大在线人数。

last_time = None:上一个事件的时间,用于定义时间段。

intervals = []:存储所有最大人数的时间段(每个时间段是元组 (start, end))。

遍历排序后的事件列表:

如果 last_time 不为 None 且与当前事件时间不同(即存在有效时间段),则检查 [last_time, current_time) 区间:

该区间内在线人数恒定为 count。

如果 count > max_count,更新 max_count = count,并重置 intervals = [(last_time, current_time)]。

如果 count == max_count,添加 (last_time, current_time) 到 intervals。

根据事件类型更新 count:+1 则 count += 1,-1 则 count -= 1。

更新 last_time = current_time。

注意:第一个事件前(last_time 为 None)和最后一个事件后无有效区间,且最后一个事件后人数通常减少,因此无需额外处理。

合并相邻时间段:

扫描后,intervals 存储了所有最大在线人数的时间段,但这些时间段可能相邻(例如 [10:00, 11:00) 和 [11:00, 12:00))。

合并相邻的时间段:遍历 intervals,如果当前时间段的结束时间等于下一个时间段的开始时间,则合并为一个连续时间段(如 [10:00, 11:00) 和 [11:00, 12:00) 合并为 [10:00, 12:00))。

输出 max_count 和合并后的时间段列表。

时间段表示:

时间段定义为左闭右开区间 [start, end),表示从 start 时间点(包含)开始,到 end 时间点(不包含)结束。例如,[10:00, 11:00) 包括 10:00 到 10:59.999,但不包括 11:00。

在输出时,可根据需要格式化为字符串(如 "10:00-11:00")。

时间复杂度
排序事件:O(n log n),其中 n 是事件数量(每个用户2个事件,n = 2 * 用户数)。

扫描事件:O(n)。

合并时间段:O(m),其中 m 是最大人数时间段的个数(通常很小)。

总体复杂度:O(n log n),主要由排序决定。

伪代码(Python 示例)
python
def find_peak_online_times(user_intervals):
# user_intervals 是列表,每个元素为 (start, end) 表示一个用户的在线时间段
events = []
for start, end in user_intervals:
events.append((start, 1)) # 登录事件,+1
events.append((end, -1)) # 登出事件,-1

# 排序事件:按时间升序,同一时间时 -1 事件在 +1 事件前
events.sort(key=lambda x: (x[0], x[1]))count = 0           # 当前在线人数
max_count = 0       # 最大在线人数
last_time = None    # 上一个事件时间
intervals = []      # 存储最大人数的时间段# 扫描事件
for time, delta in events:# 检查上一个事件到当前事件之间的区间if last_time is not None and last_time < time:# 区间 [last_time, time) 内人数恒定为 countif count > max_count:max_count = countintervals = [(last_time, time)]  # 重置为新时间段elif count == max_count:intervals.append((last_time, time))  # 添加新时间段# 更新计数count += deltalast_time = time# 合并相邻时间段
if not intervals:return max_count, []merged_intervals = []
current_start, current_end = intervals[0]
for i in range(1, len(intervals)):if intervals[i][0] == current_end:  # 相邻:当前结束 == 下一开始current_end = intervals[i][1]else:merged_intervals.append((current_start, current_end))current_start, current_end = intervals[i]
merged_intervals.append((current_start, current_end))  # 添加最后一个return max_count, merged_intervals

示例输入和输出

if name == "main":
# 示例:用户在线时间段,时间用整数分钟表示(如 10:00 为 600 分钟)
user_intervals = [
(600, 720), # 用户A: 10:00 登录, 12:00 登出
(660, 780), # 用户B: 11:00 登录, 13:00 登出
(540, 660), # 用户C: 9:00 登录, 11:00 登出
]

max_count, peak_times = find_peak_online_times(user_intervals)
print(f"最大在线人数: {max_count}")
print("时间段:")
for start, end in peak_times:# 格式化输出(假设时间整数转回 "HH:MM")start_str = f"{start//60}:{start%60:02d}"  # 简化为示例end_str = f"{end//60}:{end%60:02d}"print(f"{start_str} 到 {end_str}")
# 输出: 最大在线人数 2, 时间段 10:00 到 12:00

示例解释
输入:三个用户的在线时间段:

用户A: [10:00, 12:00)

用户B: [11:00, 13:00)

用户C: [9:00, 11:00)

事件排序后:(9:00, +1), (10:00, +1), (11:00, +1), (11:00, -1), (12:00, -1), (13:00, -1)。注意:11:00 有登录和登出事件,但登出(-1)优先处理。

扫描过程:

9:00 登录:计数=1,last_time=9:00。

10:00 登录:区间 [9:00, 10:00) 人数=1(等于当前最大),记录该区间;计数=2,last_time=10:00。

11:00 登出:区间 [10:00, 11:00) 人数=2(大于最大),更新 max_count=2,记录 [10:00, 11:00);计数=1(处理后),last_time=11:00。

11:00 登录:时间与上事件相同,跳过区间检查;计数=2,last_time=11:00。

12:00 登出:区间 [11:00, 12:00) 人数=2(等于最大),记录 [11:00, 12:00);计数=1,last_time=12:00。

13:00 登出:区间 [12:00, 13:00) 人数=1(小于最大),忽略;计数=0。

合并时间段:[10:00, 11:00) 和 [11:00, 12:00) 合并为 [10:00, 12:00)。

输出:最大在线人数为 2,时间段为 [10:00, 12:00)。

边界情况处理
无效输入:如果登出时间在登录时间前,计数可能为负。算法可处理,但建议输入校验。

同时事件:排序规则确保同一时间登出先处理,避免计数虚高。

无用户在线:如果所有时间段不重叠,最大人数可能为 1 或 0。

时间格式:实际代码中,时间应统一为可排序类型(如 datetime 对象或整数分钟)。

此方法高效且通用,适用于大量用户数据。如果有具体输入或编程语言要求,我可以提供更针对性的代码。

http://www.aitangshan.cn/news/118.html

相关文章:

  • HotSpot虚拟机对象探秘 - Charlie
  • 哨兵卫星 在线查看网站
  • ExpeRepair: Dual-Memory Enhanced LLM-based Repository-Level Program Repair 论文笔记
  • GPT5模型工程重构实践
  • rdx与edx之间的关系
  • SSRF靶场
  • ubuntu上Docker的安装与卸载
  • C++编程2025秋课堂教学
  • 防止NLP模型更新中的性能回退技术解析
  • 1431. 拥有最多糖果的孩子
  • 35页PPT|零售行业自助数据分析方法论:指标体系构建平台集成、会员与商品精细化运营实践
  • 题解:P13685 【MX-X16-T3】「DLESS-3」XOR and Impossible Problem
  • 题解:P13684 【MX-X16-T2】「DLESS-3」XOR and Multiply
  • 有没有哪个勇士能顶顶百度的网盘,限速的太恶心了
  • 库卡机器人tag焊接保护气体流量控制系统
  • 微算法科技(NASDAQ:MLGO)通过蚁群算法求解资源分配的全局最优解,实现低能耗的区块链资源分配
  • VScode编译报错:正在执行任务: CMake: build build failed. * 终端进程启动失败(退出代码: -1)。 * 终端将被任务重用,按任意键关闭。
  • 电风扇离线语音芯片方案设计与应用场景
  • Vue 中操作data中数组的方法中哪些可以触发视图更新, 哪些不可以,不可以的话有什么解决办法?
  • sublimeText安装配置插件-xml2json
  • Hbuilderx编译正常但无法打开微信开发者工具
  • solidity学习之ERC4626
  • ECharts技巧:如何按数据批次为柱状图设置不同颜色✔️♨️
  • 找到一个数的最低二进制位(lowbit)
  • 数字转人民币大写的函数
  • DP 优化专题
  • Git 常用命令总结
  • 解决 计算机有两个python环境导致 Pygal 模块导入错误
  • 详解:GPT-5 API如何在国内无限制使用?OpenAI最新发布的这款模型到底有何过人之处?
  • Linux Makefile