leetcode
leetcode 401 ~ 450
无重叠区间

无重叠区间

难度:

标签:

题目描述

给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。返回 需要移除区间的最小数量,使剩余区间互不重叠 

 

示例 1:

输入: intervals = [[1,2],[2,3],[3,4],[1,3]]
输出: 1
解释: 移除 [1,3] 后,剩下的区间没有重叠。

示例 2:

输入: intervals = [ [1,2], [1,2], [1,2] ]
输出: 2
解释: 你需要移除两个 [1,2] 来使剩下的区间没有重叠。

示例 3:

输入: intervals = [ [1,2], [2,3] ]
输出: 0
解释: 你不需要移除任何区间,因为它们已经是无重叠的了。

 

提示:

  • 1 <= intervals.length <= 105
  • intervals[i].length == 2
  • -5 * 104 <= starti < endi <= 5 * 104

代码结果

运行时间: 126 ms, 内存: 46.9 MB


/*
 * 思路:
 * 1. 首先将区间按照结束时间进行排序。
 * 2. 使用贪心算法,从第一个区间开始选择,每次选择结束时间最早且不与前一个选择的区间重叠的区间。
 * 3. 计算需要移除的区间数量。
 */
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
 
public class Solution {
    public int eraseOverlapIntervals(int[][] intervals) {
        // 按照区间的结束时间进行排序
        List<int[]> sortedIntervals = Arrays.stream(intervals)
                .sorted((a, b) -> Integer.compare(a[1], b[1]))
                .collect(Collectors.toList());
        int count = 0;
        int end = sortedIntervals.get(0)[1];
        for (int i = 1; i < sortedIntervals.size(); i++) {
            if (sortedIntervals.get(i)[0] < end) {
                // 当前区间与前一个区间重叠,计数加一
                count++;
            } else {
                // 更新结束时间
                end = sortedIntervals.get(i)[1];
            }
        }
        return count;
    }
}

解释

方法:

该题解的思路是贪心算法。首先将区间按照结束时间从小到大排序。然后从第一个区间开始,初始化一个计数器 ans 为1,表示至少有一个不重叠的区间。同时用一个变量 right 记录当前选择区间的结束时间。遍历后面的区间,如果当前区间的开始时间小于 right,说明有重叠,跳过该区间;否则,将 right 更新为当前区间的结束时间,ans 加1。最后用区间总数减去 ans,即为需要移除的最小区间数。

时间复杂度:

O(nlogn)

空间复杂度:

O(n)

代码细节讲解

🦆
在贪心选择法中,初始化 ans 为 1 代表什么意义,这是否意味着至少有一个区间不需要移除?
在贪心选择法中,初始化 ans 为 1 是基于算法从第一个区间开始选择的假设。这表明在开始时,至少有一个区间已被选为非重叠区间。因此,这确实意味着至少有一个区间不需要移除。这种初始化方法是为了简化计数逻辑,因为第一个区间自然不与任何前面的区间重叠。

相关问题

用最少数量的箭引爆气球

有一些球形气球贴在一堵用 XY 平面表示的墙面上。墙面上的气球记录在整数数组 points ,其中points[i] = [xstart, xend] 表示水平直径在 xstart 和 xend之间的气球。你不知道气球的确切 y 坐标。

一支弓箭可以沿着 x 轴从不同点 完全垂直 地射出。在坐标 x 处射出一支箭,若有一个气球的直径的开始和结束坐标为 xstartxend 且满足  xstart ≤ x ≤ xend则该气球会被 引爆 可以射出的弓箭的数量 没有限制 。 弓箭一旦被射出之后,可以无限地前进。

给你一个数组 points返回引爆所有气球所必须射出的 最小 弓箭数 

 

示例 1:

输入:points = [[10,16],[2,8],[1,6],[7,12]]
输出:2
解释:气球可以用2支箭来爆破:
-在x = 6处射出箭,击破气球[2,8]和[1,6]。
-在x = 11处发射箭,击破气球[10,16]和[7,12]。

示例 2:

输入:points = [[1,2],[3,4],[5,6],[7,8]]
输出:4
解释:每个气球需要射出一支箭,总共需要4支箭。

示例 3:

输入:points = [[1,2],[2,3],[3,4],[4,5]]
输出:2
解释:气球可以用2支箭来爆破:
- 在x = 2处发射箭,击破气球[1,2]和[2,3]。
- 在x = 4处射出箭,击破气球[3,4]和[4,5]。

 

提示:

  • 1 <= points.length <= 105
  • points[i].length == 2
  • -231 <= xstart < xend <= 231 - 1