最大不重叠区间问题详解

给定一个 $n \times 2$ 的二维数组 arr[][],表示 $n$ 个带有 起始结束 点的 区间,我们的任务是找出这组区间中数量最多的 互不重叠 的子集。

注意: 如果两个区间 [i, j][k, l] 没有任何公共点,则称它们是 不重叠(或不相交)的。
示例:

> 输入: arr[][] = [[1, 4], [2, 3], [4, 6], [8, 9]]

> 输出:

> 2 3

> 4 6

> 8 9

> 解释: 如果我们包含了 [1, 4],那么我们就不能包含 [2, 3] 和 [4 6]。

>

> 输入: arr[][] = [[1, 9], [2, 3], [5, 7]]

> 输出:

> 2 3

> 5 7

这个问题本质上是 活动选择问题 的一个变体。

[朴素方法] 生成所有子集 – $O(n^2 * 2^n)$ 时间复杂度和 $O(n)$ 空间复杂度

我们可以通过穷举所有可能的区间组合来解决这个问题。具体步骤如下:

  • 生成给定区间集合的 所有子集
  • 通过比较起始和结束时间,检查子集是否仅包含互不重叠的区间。
  • 记录下最大的有效子集。

C++


CODEBLOCK_7e57fdb3

Java


CODEBLOCK_36bd2dec

Python


CODEBLOCK_6a5ef870

[高效方法] 贪心算法 – $O(n \log n)$ 时间复杂度和 $O(1)$ 额外空间

虽然朴素方法可以解决问题,但其时间复杂度呈指数级增长,不适用于实际的大规模数据。让我们来学习一种更高效的贪心算法策略。这与活动选择问题的解法非常相似。

思路:

我们的目标是选取尽可能多的区间。如果我们总是优先选择结束时间最早的区间,那么就能为剩下的区间留出更多的时间空间。这是一种典型的贪心思想。

算法步骤:

  • 排序: 首先,我们将所有区间按照 结束时间 进行升序排序。如果两个区间的结束时间相同,我们可以选择按起始时间排序(但这对于贪心策略的正确性不是必须的,只要按结束时间排即可)。
  • 迭代选择: 初始化一个变量来记录上一个选中区间的结束时间(初始设为负无穷或第一个区间的结束时间)。遍历排序后的区间列表:

– 如果当前区间的 起始时间 大于或等于 上一个选中区间的结束时间,说明这两个区间不重叠。

– 我们将当前区间加入结果集,并更新“上一个选中区间的结束时间”为当前区间的结束时间。

– 否则,跳过当前区间(因为如果选了它,就会发生重叠,且由于我们是按结束时间排序的,选它肯定不如选之前那个结束得更早的区间优)。

让我们来看看具体的代码实现:

C++


CODEBLOCK_7f073563

Java


CODEBLOCK_8b3ff747

Python


CODEBLOCK_1414cfeb

复杂度分析:

  • 时间复杂度: $O(n \log n)$。主要的时间开销在于对区间数组进行排序。遍历一次数组只需要 $O(n)$ 的时间。
  • 空间复杂度: $O(1)$(如果忽略存储结果所需的输出空间)。我们不需要额外的空间来存储辅助数据结构(如果排序是原地进行的)。
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。如需转载,请注明文章出处豆丁博客和来源网址。https://shluqu.cn/42267.html
点赞
0.00 平均评分 (0% 分数) - 0