用C++的sort函数搞定PTA老板作息表:一个排序思路解决所有时间区间合并问题
用C的sort函数搞定PTA老板作息表一个排序思路解决所有时间区间合并问题清晨四点三十分当大多数人还在梦乡时某位老板的作息表已经在社交媒体上引发热议。这份看似严谨的时间安排却被细心的网友发现存在明显的空白时段。这不禁让人思考如何用算法快速找出时间表中的漏洞这正是PTAProgramming Talent Assessment中L2-042题目的核心挑战。对于学习算法和数据结构的C开发者而言这类时间区间处理问题绝非孤例。从合并重叠区间到查找间隙类似的模式在LeetCode等编程题库中反复出现。本文将揭示一个通用解法通过标准库中的sort函数配合简单的线性扫描就能优雅解决这类问题。无论你是正在备战PTA考试还是希望提升算法思维这个技巧都将成为你的利器。1. 问题本质与算法选择时间间隙查找问题看似复杂实则可以被抽象为一个经典的区间处理模型。给定一组可能重叠或非连续的时间区间我们需要找出所有未被覆盖的时间段。这类问题在现实中有广泛的应用场景日程安排系统检测会议之间的空闲时段网络监控识别服务器无响应的时间窗口资源分配查找设备未被占用的时间段解决这类问题的关键在于两个核心步骤区间排序将所有区间按起始时间升序排列线性扫描依次比较相邻区间的端点关系struct TimeInterval { string start; string end; }; bool compareIntervals(const TimeInterval a, const TimeInterval b) { return a.start b.start; }表区间合并问题的核心处理步骤对比步骤操作时间复杂度空间复杂度1. 排序使用sort函数对区间排序O(n log n)O(1)2. 扫描线性遍历比较相邻区间O(n)O(1)总计-O(n log n)O(1)2. C实现详解让我们深入分析PTA原题的解决方案。完整的实现仅需不到50行代码却包含了处理时间区间问题的所有精髓。关键数据结构设计我们首先定义一个简单的结构体来存储时间区间struct TimeSegment { string begin; string end; } segments[100000];排序逻辑C标准库的sort函数配合自定义比较器可以轻松实现区间排序bool compareSegments(const TimeSegment a, const TimeSegment b) { return a.begin b.begin; } // 在main函数中调用 sort(segments, segments n, compareSegments);提示字符串形式的时间比较之所以可行是因为hh:mm:ss格式的字典序与时序完全一致。例如08:00:00 09:00:00。间隙检测算法排序后我们只需维护当前覆盖区间的末端依次检查每个区间的开始时间string currentEnd 00:00:00; for (int i 0; i n; i) { if (currentEnd segments[i].begin) { cout currentEnd - segments[i].begin endl; } currentEnd max(currentEnd, segments[i].end); } if (currentEnd 23:59:59) { cout currentEnd - 23:59:59 endl; }3. 边界条件与常见陷阱在实际编码中有几个关键细节需要特别注意输入格式处理时间区间中间的短横线需要用字符变量吸收char dash; // 用于存储- cin segments[i].begin dash segments[i].end;初始状态设置当前末端应初始化为一天的开始时间(00:00:00)最终检查不要忘记检查最后一个区间与一天结束时间(23:59:59)之间的间隙时间比较的特殊性虽然字符串比较适用于本题但对于更复杂的时间格式应考虑转换为秒数再比较常见错误列表忘记处理输入中的分隔符未考虑第一个区间之前可能存在的间隙遗漏最后一个区间之后的检查错误假设输入区间已经排序4. 算法扩展与应用掌握了这个基础模式后我们可以轻松应对各种变体问题。以下是几个典型的应用场景LeetCode 56. 合并区间给定一组可能重叠的区间合并所有重叠的区间。解决方案只需稍作修改vectorvectorint merge(vectorvectorint intervals) { if (intervals.empty()) return {}; sort(intervals.begin(), intervals.end()); vectorvectorint merged; for (const auto interval : intervals) { if (merged.empty() || merged.back()[1] interval[0]) { merged.push_back(interval); } else { merged.back()[1] max(merged.back()[1], interval[1]); } } return merged; }会议室预定系统判断一个人是否能参加所有会议LeetCode 252本质是检查区间是否有重叠bool canAttendMeetings(vectorvectorint intervals) { sort(intervals.begin(), intervals.end()); for (int i 1; i intervals.size(); i) { if (intervals[i][0] intervals[i-1][1]) { return false; } } return true; }表区间处理问题的常见变体及解法问题类型核心思路典型例题查找间隙比较相邻区间的端点PTA L2-042合并重叠更新当前区间的末端LeetCode 56插入新区间先插入再合并LeetCode 57计算覆盖长度累加非重叠区间长度LeetCode 22895. 性能优化与进阶思考虽然O(n log n)的时间复杂度已经相当高效但在特定场景下仍有优化空间如果输入已排序可以跳过排序步骤直接线性扫描O(n)时间处理大规模数据考虑分治策略或并行处理内存优化对于固定格式的时间可以转换为整数存储如从00:00:00开始的秒数对于时间处理特别密集的场景我们可以设计更高效的时间表示int timeToSeconds(const string time) { int h stoi(time.substr(0, 2)); int m stoi(time.substr(3, 2)); int s stoi(time.substr(6, 2)); return h * 3600 m * 60 s; } string secondsToTime(int total) { int h total / 3600; int m (total % 3600) / 60; int s total % 60; char buffer[9]; sprintf(buffer, %02d:%02d:%02d, h, m, s); return string(buffer); }在实际项目中这种区间处理技巧可以应用于日历应用的冲突检测网络服务的可用性监控资源调度系统的空闲时段查找