排序题目:插入区间

题目

标题和出处

标题:插入区间

出处:57. 插入区间

难度

5 级

题目描述

要求

给定无重叠的区间数组 intervals \texttt{intervals} intervals,其中 intervals[i]   =   [start i ,   end i ] \texttt{intervals[i] = [start}_\texttt{i}\texttt{, end}_\texttt{i}\texttt{]} intervals[i] = [starti, endi],表示第 i \texttt{i} i 个区间的开始位置和结束位置, intervals \texttt{intervals} intervals 按照 start i \texttt{start}_\texttt{i} starti 升序排序。同时给定一个区间 newInterval   =   [start,   end] \texttt{newInterval = [start, end]} newInterval = [start, end],表示另一个区间的开始位置和结束位置。

newInterval \texttt{newInterval} newInterval 插入到 intervals \texttt{intervals} intervals 中,使得 intervals \texttt{intervals} intervals 仍按照 start i \texttt{start}_\texttt{i} starti 升序排序且 intervals \texttt{intervals} intervals 仍没有重叠的区间(必要的情况下合并重叠的区间)。

返回插入区间后的 intervals \texttt{intervals} intervals

示例

示例 1:

输入: intervals   =   [[1,3],[6,9]],   newInterval   =   [2,5] \texttt{intervals = [[1,3],[6,9]], newInterval = [2,5]} intervals = [[1,3],[6,9]], newInterval = [2,5]
输出: [[1,5],[6,9]] \texttt{[[1,5],[6,9]]} [[1,5],[6,9]]

示例 2:

输入: intervals   =   [[1,2],[3,5],[6,7],[8,10],[12,16]],   newInterval   =   [4,8] \texttt{intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]} intervals = [[1,2],[3,5],[6,7],[8,10],[12,16]], newInterval = [4,8]
输出: [[1,2],[3,10],[12,16]] \texttt{[[1,2],[3,10],[12,16]]} [[1,2],[3,10],[12,16]]
解释:因为新的区间 [4,8] \texttt{[4,8]} [4,8] [3,5],[6,7],[8,10] \texttt{[3,5],[6,7],[8,10]} [3,5],[6,7],[8,10] 重叠。

数据范围

  • 1 ≤ intervals.length ≤ 10 4 \texttt{1} \le \texttt{intervals.length} \le \texttt{10}^\texttt{4} 1intervals.length104
  • intervals[i].length = 2 \texttt{intervals[i].length} = \texttt{2} intervals[i].length=2
  • 0 ≤ start i ≤ end i ≤ 10 5 \texttt{0} \le \texttt{start}_\texttt{i} \le \texttt{end}_\texttt{i} \le \texttt{10}^\texttt{5} 0startiendi105
  • intervals \texttt{intervals} intervals 根据 start i \texttt{start}_\texttt{i} starti升序排序
  • newInterval.length = 2 \texttt{newInterval.length} = \texttt{2} newInterval.length=2
  • 0 ≤ start ≤ end ≤ 10 5 \texttt{0} \le \texttt{start} \le \texttt{end} \le \texttt{10}^\texttt{5} 0startend105

解法一

思路和算法

这道题是「合并区间」的延伸,要求在已经有序的无重叠区间数组中插入一个新区间,插入之后合并重叠的区间,使得插入区间后的数组仍然满足有序且无重叠区间。

由于插入区间的操作等价于在数组中增加一个区间然后合并重叠区间,并保持区间有序,因此可以使用「合并区间」的做法。使用一个列表存储数组 intervals \textit{intervals} intervals 中的所有区间和新区间,将列表中的所有重叠区间合并。

首先将列表中的所有区间(包括新区间)按照开始位置升序排序,如果存在多个区间的开始位置相同则按照结束位置降序排序,然后遍历排序后的列表,合并重叠的区间。由于列表中的区间按照开始位置升序排序,因此合并重叠区间之后,列表中的区间符合按照开始位置升序排序的规则。

遍历结束之后,将列表转成数组返回。

代码

class Solution {
    public int[][] insert(int[][] intervals, int[] newInterval) {
        List<int[]> intervalList = new ArrayList<int[]>();
        for (int[] interval : intervals) {
            intervalList.add(interval);
        }
        intervalList.add(newInterval);
        Collections.sort(intervalList, (a, b) -> {
            if (a[0] != b[0]) {
                return a[0] - b[0];
            } else {
                return b[1] - a[1];
            }
        });
        List<int[]> mergedList = new ArrayList<int[]>();
        mergedList.add(intervalList.get(0));
        int size = intervalList.size();
        for (int i = 1; i < size; i++) {
            int[] curr = intervalList.get(i);
            int[] prev = mergedList.get(mergedList.size() - 1);
            if (curr[0] == prev[0]) {
                continue;
            }
            if (curr[0] <= prev[1]) {
                prev[1] = Math.max(prev[1], curr[1]);
            } else {
                mergedList.add(curr);
            }
        }
        return mergedList.toArray(new int[mergedList.size()][]);
    }
}

复杂度分析

  • 时间复杂度: O ( n log ⁡ n ) O(n \log n) O(nlogn),其中 n n n 是数组 intervals \textit{intervals} intervals 的长度。排序需要 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的时间,排序后遍历列表合并区间需要 O ( n ) O(n) O(n) 的时间,时间复杂度是 O ( n log ⁡ n ) O(n \log n) O(nlogn)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 intervals \textit{intervals} intervals 的长度。列表需要 O ( n ) O(n) O(n) 的空间。

解法二

思路和算法

由于数组 intervals \textit{intervals} intervals 已经有序,因此可以直接遍历数组 intervals \textit{intervals} intervals 完成插入 newInterval \textit{newInterval} newInterval 的操作。

遍历数组 intervals \textit{intervals} intervals 的过程中,使用列表存储插入操作后的结果区间,应确保遍历所有区间(包括已有的区间和新区间)的顺序是按照开始位置升序的顺序,依次将每个遍历到的区间添加到列表。用 curr \textit{curr} curr 表示当前遍历到的区间,如果 newInterval \textit{newInterval} newInterval 尚未插入且 curr [ 0 ] ≥ newInterval [ 0 ] \textit{curr}[0] \ge \textit{newInterval}[0] curr[0]newInterval[0],则在将 curr \textit{curr} curr 添加到列表之前,首先将 newInterval \textit{newInterval} newInterval 添加到列表。

每次将区间添加到列表的同时,判断新添加的区间是否和列表中已有的区间存在重叠,如果存在重叠则执行合并操作。由于遍历区间的顺序是按照开始位置升序的顺序,且列表中已有的区间互不重叠,因此当列表不为空时,只需要将新添加的区间和列表中的最后一个区间比较即可。具体操作如下。

  • 如果列表不为空且当前区间的开始位置小于等于列表中的最后一个区间的结束位置,则将当前区间与列表中的最后一个区间合并,将列表中的最后一个区间的结束位置更新为两个区间的结束位置中的最大值。

  • 如果列表为空或当前区间的开始位置大于列表中的最后一个区间的结束位置,则将当前区间添加到列表中。

遍历结束之后,如果 newInterval \textit{newInterval} newInterval 仍未插入,则将 newInterval \textit{newInterval} newInterval 添加到列表。

最后将列表转成数组返回。

代码

class Solution {
    public int[][] insert(int[][] intervals, int[] newInterval) {
        List<int[]> intervalList = new ArrayList<int[]>();
        boolean inserted = false;
        int length = intervals.length;
        for (int i = 0; i < length; i++) {
            int[] curr = intervals[i];
            if (!inserted && curr[0] >= newInterval[0]) {
                insertInterval(intervalList, newInterval);
                inserted = true;
            }
            insertInterval(intervalList, curr);
        }
        if (!inserted) {
            insertInterval(intervalList, newInterval);
        }
        return intervalList.toArray(new int[intervalList.size()][]);
    }

    public void insertInterval(List<int[]> intervalList, int[] interval) {
        boolean merged = false;
        if (!intervalList.isEmpty()) {
            int[] prev = intervalList.get(intervalList.size() - 1);
            if (interval[0] <= prev[1]) {
                prev[1] = Math.max(prev[1], interval[1]);
                merged = true;
            }
        }
        if (!merged) {
            intervalList.add(interval);
        }
    }
}

复杂度分析

  • 时间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 intervals \textit{intervals} intervals 的长度。需要遍历数组 intervals \textit{intervals} intervals 一次完成区间的插入,对于每个区间的操作时间都是 O ( 1 ) O(1) O(1)

  • 空间复杂度: O ( n ) O(n) O(n),其中 n n n 是数组 intervals \textit{intervals} intervals 的长度。存储合并后的区间的列表需要 O ( n ) O(n) O(n) 的空间。

  • 43
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

伟大的车尔尼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值