【忍者算法】从日程安排到区间合并:探索合并区间问题|LeetCode 56 合并区间

从日程安排到区间合并:探索合并区间问题

生活中的算法

想象你是一位活动策划师,桌上摆着许多便利贴,每张写着不同的活动时间段:9:00-11:00的晨会、10:30-12:00的培训、14:00-16:00的项目汇报、15:00-17:00的团队建设...有些活动时间明显重叠了,为了让日程更清晰,你需要将这些重叠的时间段合并起来。比如晨会和培训重叠了,就可以合并为9:00-12:00的一个大时间段。

这种情况在生活中随处可见。比如医院的预约时段合并、健身房的预定时间优化、公司会议室的档期管理,甚至是地铁维修时段的规划等。

问题描述

LeetCode第56题"合并区间"是这样描述的:给出一个区间的集合,请合并所有重叠的区间。

例如:

输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠,将它们合并为 [1,6]

最直观的解法:暴力合并

就像你整理日程表一样,最直观的方法是:拿起每张便利贴,和其他所有便利贴比较,看看能否合并。

让我们用一个简单的例子来理解:

时间段:[[1,4], [2,3], [3,6]]
1. 比较[1,4][2,3]21-4之间,合并为[1,4]
2. 再比较[1,4][3,6]31-4之间,46相邻,合并为[1,6]
最终得到:[[1,6]]

优化解法:排序后合并

仔细想想,如果我们先把所有时间段按开始时间排序,就像把便利贴按时间顺序贴在墙上,那么我们只需要一次遍历就能完成合并。这就像你在整理行程时,先按时间排好序,然后逐个看相邻的档期能否合并。

排序合并的原理

就像理财一样:

  1. 先把所有区间按开始时间排序(就像把账单按日期排序)
  2. 对于每个新区间,看它是否能和当前累积的区间合并:
    • 如果新区间的开始时间在当前区间的结束时间之前,就应该合并(就像新的收入在之前的投资周期结束前就到了,应该一起考虑)
    • 如果新区间和当前区间完全分离,就把当前区间存起来,开始新的累积(就像开始一个全新的投资周期)

示例运行

用日程安排的例子来说明:

原始日程:[[9,11], [10,12], [14,16], [15,17]]

1. 排序后(已按开始时间排好):
   [[9,11], [10,12], [14,16], [15,17]]

2. 处理[9,11]:
   当前合并结果 = [[9,11]]

3. 看[10,12]:
   10点在9-11内,可以合并
   当前合并结果 = [[9,12]]

4. 看[14,16]:
   14点不在9-12内,存储之前结果,开始新区间
   当前合并结果 = [[9,12], [14,16]]

5. 看[15,17]:
   1514-16内,可以合并
   最终结果 = [[9,12], [14,17]]

Java代码实现

public int[][] merge(int[][] intervals) {
    if (intervals == null || intervals.length <= 1) {
        return intervals;
    }
    
    // 按开始时间排序
    Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
    
    List<int[]> result = new ArrayList<>();
    int[] current = intervals[0];  // 当前正在处理的区间
    
    for (int i = 1; i < intervals.length; i++) {
        // 如果当前区间的结束时间 >= 下一个区间的开始时间,合并
        if (current[1] >= intervals[i][0]) {
            // 更新结束时间为两者中的较大值
            current[1] = Math.max(current[1], intervals[i][1]);
        } else {
            // 无法合并,保存当前区间,开始新区间
            result.add(current);
            current = intervals[i];
        }
    }
    
    // 别忘了最后一个区间
    result.add(current);
    
    return result.toArray(new int[result.size()][]);
}

解法比较

让我们比较这两种方法:

暴力合并:

  • 时间复杂度:O(n²)
  • 空间复杂度:O(1)
  • 优点:直观易懂
  • 缺点:效率较低,特别是当区间很多时

排序后合并:

  • 时间复杂度:O(nlogn),主要是排序的开销
  • 空间复杂度:O(n),用于存储结果
  • 优点:高效且实现简单
  • 缺点:需要额外空间存储结果

实用技巧总结

解决此类区间问题的关键点:

  1. 考虑是否需要预处理(如排序)
  2. 注意区间的开始和结束位置
  3. 处理边界情况
  4. 别忘了最后一个区间

类似的问题还有:

  • 会议室预订
  • 插入区间
  • 区间列表的交集

小结

通过合并区间这道题,我们学会了如何高效地处理重叠区间问题。这个技巧不仅能解决算法题,在实际工作中处理时间安排、资源分配等问题时也很有用。记住,当遇到需要处理重叠区间的问题时,先排序再合并往往是一个简单而高效的解决方案!


作者:忍者算法
公众号:忍者算法

我准备了一份刷题清单,以及这些题目的详细题解,覆盖了绝大部分常见面试题。我可以很负责任地说,只要你把这些题真正掌握了,80%的算法面试都能遇到相似题目。公众号回复【刷题清单】获取~

posted @   忍者算法  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 本地部署 DeepSeek:小白也能轻松搞定!
· 传国玉玺易主,ai.com竟然跳转到国产AI
· 自己如何在本地电脑从零搭建DeepSeek!手把手教学,快来看看! (建议收藏)
· 我们是如何解决abp身上的几个痛点
· 如何基于DeepSeek开展AI项目
点击右上角即可分享
微信分享提示