当前位置: 首页 > article >正文

排序题目:插入区间

文章目录

  • 题目
    • 标题和出处
    • 难度
    • 题目描述
      • 要求
      • 示例
      • 数据范围
  • 解法一
    • 思路和算法
    • 代码
    • 复杂度分析
  • 解法二
    • 思路和算法
    • 代码
    • 复杂度分析

题目

标题和出处

标题:插入区间

出处: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) 的空间。


http://www.kler.cn/a/292098.html

相关文章:

  • 如何知道表之间的关系(为了知识图谱的构建)
  • DAY120java审计第三方组件依赖库挖掘FastjsonShiroLog4jH2DB
  • 计算机网络WebSocket——针对实习面试
  • EXCEL 或 WPS 列下划线转驼峰
  • c++原型模式(Prototype Pattern)
  • HTML5实现俄罗斯方块小游戏
  • 趋势!遥感再发Nature正刊!
  • 一个webpack的plugin 的简单例子
  • python黄金分割数
  • 华为达芬奇人像引擎2.0,人像体验有哪些升级
  • 计算机毕业设计选题推荐-客栈管理系统-酒店预订-民宿管理系统-Java/Python项目实战
  • IDEA 2024最新软件下载
  • HarmonyOS开发实战( Beta5版)线程间通信场景最佳实践
  • linux curl命令介绍以及使用
  • React 通用后台管理项目
  • 消息队列RabbitMQ
  • 第8讲 ,ISP 串口程序下载
  • C# 字符串(String)使用教程
  • LeetCode2.两数相加
  • Monorepo学习笔记
  • react 子组件调用父组件方法,获取的数据不是最新值
  • 常用网络协议理解
  • 加锁造成的线程优先级反转
  • 搜维尔科技:使用Facewaer面部捕捉系统制作栩栩如生的脸部动画
  • Maven 的 pom.xml 文件中<dependency> 元素及其各个参数的解释
  • EmguCV学习笔记 C# 10.1 人脸检测 CascadeClassifier类