☰
区间查询算法:统计特定时间点的学生作业人数
2026/11/4 8:51:41 网站建设 项目流程

1. 问题分析与解法思路

这道题目要求我们统计在特定时间点(queryTime)正在做作业的学生人数。每个学生都有一个开始时间和结束时间,我们需要判断queryTime是否落在某个学生的[startTime, endTime]区间内。

1.1 问题理解与建模

这个问题可以抽象为一个区间查询问题:给定n个闭区间[startTime[i], endTime[i]],查询有多少个区间包含给定的queryTime点。从数学角度来说,就是求满足startTime[i] ≤ queryTime ≤ endTime[i]的区间数量。

1.2 暴力解法分析

最直观的解法就是遍历所有学生,检查每个学生的作业时间区间是否包含queryTime。这种解法的时间复杂度是O(n),其中n是学生数量。对于LeetCode的题目规模来说,这个复杂度是完全可接受的。

注意:虽然题目看起来简单,但实际面试中可能会考察边界条件的处理能力,比如空输入、queryTime超出所有区间范围等情况。

2. 代码实现与优化

2.1 基础实现

给出的C++实现已经很好地解决了这个问题:

class Solution { public: int busyStudent(vector<int>& startTime, vector<int>& endTime, int queryTime) { int ans = 0; int n = startTime.size(); for(int i = 0; i < n; i++) { if(startTime[i] <= queryTime && endTime[i] >= queryTime) ans++; } return ans; } };

2.2 代码优化空间

虽然这个解法已经足够高效,但我们还可以考虑一些优化:

  1. 提前终止循环:如果startTime和endTime是有序的,可以在某些情况下提前终止循环
  2. 并行计算:对于非常大的数据集,可以考虑使用并行计算来加速
  3. 预处理:如果queryTime需要多次查询,可以预处理数据建立更高效的数据结构

2.3 边界条件处理

在实际编码中,我们需要考虑以下边界情况:

  • 空输入(startTime或endTime为空)
  • queryTime小于所有startTime
  • queryTime大于所有endTime
  • startTime[i] > endTime[i]的情况(题目中假设不会出现)

3. 算法复杂度分析

3.1 时间复杂度

该算法的时间复杂度是O(n),因为需要遍历所有n个学生一次。这是最优的渐进复杂度,因为任何解法至少需要检查每个学生一次。

3.2 空间复杂度

空间复杂度是O(1),只使用了常数级别的额外空间(ans和n变量)。

4. 类似问题与扩展

4.1 LeetCode类似题目

  1. 252. 会议室:判断一个人是否能参加所有会议
  2. 253. 会议室 II:计算需要的最少会议室数量
  3. 56. 合并区间:合并所有重叠的区间

4.2 实际应用场景

这类区间问题在实际开发中有广泛应用:

  • 会议室预定系统
  • 课程时间表安排
  • 任务调度系统
  • 日历应用中的时间冲突检测

4.3 进阶思考

如果问题变为需要处理大量查询(多个queryTime),我们可以考虑以下优化:

  1. 对区间进行排序,然后对每个查询使用二分查找
  2. 使用线段树或树状数组等数据结构
  3. 使用前缀和数组预处理

5. 面试技巧与注意事项

5.1 面试常见问题

在面试中遇到这类问题时,可以按照以下步骤进行:

  1. 明确问题要求,确认输入输出
  2. 提出暴力解法并分析复杂度
  3. 思考优化空间
  4. 处理边界条件
  5. 编写代码并测试

5.2 代码风格建议

  1. 使用有意义的变量名(如count代替ans)
  2. 添加必要的注释
  3. 考虑使用更现代的C++特性(如范围for循环)
  4. 添加输入验证(如果允许)

5.3 测试用例设计

好的测试用例应该包括:

  • 普通情况(多个区间,queryTime在中间)
  • 边界情况(queryTime等于某个startTime或endTime)
  • 极端情况(所有区间都包含/不包含queryTime)
  • 空输入情况

6. 个人实战经验分享

在实际解决这类区间问题时,我发现以下几点特别重要:

  1. 画图辅助理解:在纸上画出时间轴和区间,可以更直观地理解问题
  2. 先考虑简单情况:从少量区间(如2-3个)开始,逐步扩展到一般情况
  3. 注意区间开闭:明确题目要求的是开区间还是闭区间
  4. 测试边界条件:特别是区间端点和queryTime相等的情况

提示:在面试中,即使问题看起来很简单,也要考虑各种边界情况并主动提出,这能展示你的全面思考能力。

7. 不同语言实现对比

虽然C++实现已经很简洁,但其他语言也有各自的特色:

7.1 Python实现

def busyStudent(startTime, endTime, queryTime): return sum(1 for s, e in zip(startTime, endTime) if s <= queryTime <= e)

Python的实现更加简洁,利用了生成器表达式和zip函数。

7.2 Java实现

class Solution { public int busyStudent(int[] startTime, int[] endTime, int queryTime) { int count = 0; for (int i = 0; i < startTime.length; i++) { if (startTime[i] <= queryTime && queryTime <= endTime[i]) { count++; } } return count; } }

Java实现与C++类似,但需要注意数组长度的获取方式不同。

7.3 JavaScript实现

var busyStudent = function(startTime, endTime, queryTime) { return startTime.reduce((count, s, i) => s <= queryTime && endTime[i] >= queryTime ? count + 1 : count, 0); };

JavaScript可以使用reduce方法实现函数式风格的解法。

8. 性能优化深入探讨

虽然O(n)的解法已经足够好,但如果数据量极大(如数百万学生),我们可以考虑以下优化:

8.1 并行计算

使用多线程将学生列表分割处理,最后合并结果。这在现代多核CPU上可以显著提升性能。

8.2 向量化运算

某些语言/框架支持SIMD指令,可以同时对多个数据进行相同的比较操作。

8.3 预处理排序

如果queryTime需要多次查询,可以先对区间进行排序,然后对每个查询使用二分查找:

  1. 按startTime排序,找到startTime <= queryTime的所有区间
  2. 在这些区间中,统计endTime >= queryTime的数量

这种方法可以将每次查询的时间复杂度降低到O(log n)。

9. 实际工程应用思考

在实际工程中,这类问题可能会以更复杂的形式出现:

9.1 数据库实现

如果数据存储在数据库中,可以用一条SQL查询解决:

SELECT COUNT(*) FROM students WHERE start_time <= :queryTime AND end_time >= :queryTime

9.2 分布式处理

对于超大规模数据,可以使用MapReduce框架:

  1. Map阶段:每个节点统计本地符合条件的学生数
  2. Reduce阶段:汇总所有节点的计数

9.3 实时系统考虑

在实时系统中,可能需要维护一个高效的数据结构来支持频繁的查询和更新操作,这时可以考虑使用:

  • 线段树
  • 树状数组
  • 跳表等高级数据结构

10. 算法竞赛中的变种

在算法竞赛中,这类问题可能会有以下变种:

  1. 动态版本:允许动态添加/删除区间,同时支持查询
  2. 多维版本:区间扩展到多维空间
  3. 加权版本:每个区间有权重,查询总权重而非计数
  4. 模糊查询:查询时间是一个区间而非单个点

对于这些变种问题,通常需要更复杂的数据结构和算法来解决。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询