PTA天梯赛L2-042题保姆级攻略:用C++ STL vector和sort轻松找出老板作息表的‘摸鱼’时间
PTA天梯赛L2-042题解用侦探思维破解老板的摸鱼时间最近在PTA天梯赛的题库中有一道关于时间区间处理的题目引起了我的注意。题目描述了一位老板在网上晒出自己的作息时间表却被眼尖的网友发现存在时间空白。这让我想起了一个有趣的比喻我们就像数字侦探要从看似完整的时间表中找出那些被刻意隐藏的摸鱼时刻。这道题编号L2-042考察的核心是如何处理不连续的时间区间并找出其中的空白。对于准备算法竞赛的同学来说这不仅是练习STL使用的绝佳机会更是培养问题分解能力的典型案例。下面我将从解题思路、代码实现到优化技巧带你一步步揭开这道题的神秘面纱。1. 问题分析与建模首先我们需要明确题目的具体要求。给定N个时间段每个时间段格式为hh:mm:ss - hh:mm:ss要求找出一天中未被这些时间段覆盖的所有区间。这些区间需要按时间顺序输出且题目保证输入的时间段不会重叠。关键观察点所有时间都在00:00:00到23:59:59之间输入区间按任意顺序给出相邻区间可能有端点重合如A区间结束于08:00:00B区间开始于08:00:00需要检查三个边界开始前、中间间隙、结束后我们可以将这个问题建模为在时间线上寻找空隙的过程。想象一条从00:00:00到23:59:59的时间轴上面已经标记了一些线段输入的时间段我们的任务是找出所有未被线段覆盖的部分。2. 解题思路与算法设计解决这个问题的关键在于如何高效地处理时间区间并找出间隙。以下是详细的思考过程2.1 输入处理与存储首先需要将输入的时间段存储起来。由于题目中的时间都是字符串格式我们可以直接使用vectorstring来保存原始输入。但更高效的做法是将时间转换为秒数方便比较和排序。struct Time { int h, m, s; int toSeconds() const { return h * 3600 m * 60 s; } }; vectorpairTime, Time timeIntervals;2.2 时间区间排序未排序的时间区间难以处理我们需要先按开始时间进行排序bool compareIntervals(const pairTime, Time a, const pairTime, Time b) { return a.first.toSeconds() b.first.toSeconds(); } sort(timeIntervals.begin(), timeIntervals.end(), compareIntervals);2.3 寻找间隙的算法排序后我们可以按顺序检查相邻区间之间的间隙检查第一个区间是否从00:00:00开始检查相邻两个区间之间是否有间隙检查最后一个区间是否到23:59:59结束算法伪代码if 第一个区间的开始 00:00:00 输出 00:00:00 - 第一个区间的开始 for 每个相邻的区间对 (A, B): if A的结束 B的开始 输出 A的结束 - B的开始 if 最后一个区间的结束 23:59:59 输出 最后一个区间的结束 - 23:59:593. 完整代码实现与解析基于上述思路我们可以实现完整的解决方案。以下是使用C STL的详细代码#include iostream #include vector #include algorithm using namespace std; struct Time { int h, m, s; static Time fromString(const string str) { Time t; sscanf(str.c_str(), %d:%d:%d, t.h, t.m, t.s); return t; } int toSeconds() const { return h * 3600 m * 60 s; } string toString() const { char buffer[9]; sprintf(buffer, %02d:%02d:%02d, h, m, s); return string(buffer); } }; void printGap(const Time start, const Time end) { cout start.toString() - end.toString() endl; } int main() { int N; cin N; cin.ignore(); // 消耗换行符 vectorpairTime, Time intervals; for (int i 0; i N; i) { string line; getline(cin, line); Time start Time::fromString(line.substr(0, 8)); Time end Time::fromString(line.substr(11, 8)); intervals.emplace_back(start, end); } // 按开始时间排序 sort(intervals.begin(), intervals.end(), [](const auto a, const auto b) { return a.first.toSeconds() b.first.toSeconds(); }); // 检查开始前的间隙 Time dayStart Time{0, 0, 0}; if (intervals[0].first.toSeconds() dayStart.toSeconds()) { printGap(dayStart, intervals[0].first); } // 检查中间间隙 for (size_t i 0; i intervals.size() - 1; i) { const auto curr intervals[i]; const auto next intervals[i1]; if (curr.second.toSeconds() next.first.toSeconds()) { printGap(curr.second, next.first); } } // 检查结束后的间隙 Time dayEnd Time{23, 59, 59}; if (intervals.back().second.toSeconds() dayEnd.toSeconds()) { printGap(intervals.back().second, dayEnd); } return 0; }代码关键点解析Time结构体封装了时间处理逻辑包括字符串转换和秒数计算使用vectorpairTime, Time存储时间区间比直接处理字符串更清晰排序使用lambda表达式按开始时间的秒数比较三个检查步骤分别处理开始前、中间和结束后的间隙4. 优化与边界条件处理在实际编码中我们需要特别注意一些边界条件和可能的优化点4.1 输入处理优化原始代码中直接使用字符串比较虽然简单但不够健壮。我们改进后的版本将时间转换为结构体具有以下优势更清晰的类型系统更容易进行时间计算和比较减少字符串操作错误4.2 边界条件检查需要特别注意以下几种边界情况只有一个时间区间的情况时间区间正好从00:00:00开始或到23:59:59结束相邻区间端点恰好重合的情况题目保证不会重叠但可能端点重合测试用例示例输入 1 12:00:00 - 13:00:00 输出 00:00:00 - 12:00:00 13:00:00 - 23:59:594.3 性能分析时间复杂度O(N log N)主要由排序步骤决定空间复杂度O(N)存储所有时间区间对于PTA天梯赛的数据规模(N ≤ 1000)这个算法完全足够5. 常见错误与调试技巧在解决这类区间问题时初学者常会遇到一些典型错误5.1 时间比较错误直接使用字符串比较时间可能导致错误结果// 错误示例字符串比较 if (08:59:59 09:00:00) // 可能正确但不推荐正确做法是转换为秒数或使用专门的时间结构体比较。5.2 区间端点处理不当题目说明区间至少间隔1秒且不会重叠但可能有端点重合。例如07:10:59 - 08:00:00 08:00:00 - 09:00:00这两个区间是连续的中间没有间隙不应输出。5.3 输入格式处理使用getline读取输入时需要注意处理换行符cin N; cin.ignore(); // 消耗掉数字后的换行符5.4 输出格式要求输出必须严格匹配题目要求的格式包括前导零和分隔符04:30:00 - 05:30:00 // 正确 4:30:0 - 5:30:0 // 错误6. 扩展思考与实际应用这道题目虽然来自算法竞赛但其核心思想在实际开发中有广泛应用日程安排系统检测用户日程表中的空闲时间段资源预订系统找出未被预订的时间段日志分析识别系统活动中的静默期网络监控发现服务中断的时间窗口理解这类区间处理问题的通用解法可以帮助我们解决许多实际问题。例如在处理会议室预订系统时类似的算法可以用来查找可用的时间段。进一步挑战如果时间区间可能重叠如何合并区间后再找间隙如果需要处理跨越多天的时间段算法该如何调整如何优化算法以处理大规模数据如N 1,000,0007. 竞赛技巧与STL使用心得在算法竞赛中合理使用STL可以大幅提高编码效率和正确率。对于这道题我们主要使用了vector动态数组存储时间区间sort对区间进行排序pair组合开始和结束时间STL使用建议熟悉常用容器的接口和特性掌握自定义比较函数的方法lambda表达式很实用注意迭代器的有效性和边界条件对于复杂数据结构考虑定义辅助类型如我们的Time结构体在最近的PTA天梯赛中这类考察基础数据结构应用和问题分解能力的题目越来越常见。通过这道题我们不仅学会了如何处理时间区间更重要的是培养了将实际问题抽象为计算模型的能力。