leetcode热题HOT 56. 合并区间(含二维数组排序)

一、问题描述:

以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
示例 1:
输入:intervals = [[1,3],[2,6],[8,10],[15,18]]
输出:[[1,6],[8,10],[15,18]]
解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6].
示例 2:
输入:intervals = [[1,4],[4,5]]
输出:[[1,5]]
解释:区间 [1,4] 和 [4,5] 可被视为重叠区间。

二、解题思路:

  1. 首先,我们将列表中的区间按照左端点升序排序。然后我们将第一个区间记录在pre中,并按顺序依次考虑之后的每个区间:
    ①如果当前区间的左端点在pre的右端点之后,那么它们不会重合,我们可以直接将pre加入数组result的末尾,更新pre为当前区间;
    ②否则,它们重合,我们需要用当前区间的右端点更新pre的右端点,将其置为二者的较大值。
  2. 具体步骤:
    ①首先判断如果输入的区间数组长度为1,则直接返回该数组。
    ②使用 Arrays.sort 对输入的区间数组按照区间起始位置进行排序。
    ③初始化一个 LinkedList<int[]> result 用于存储最终合并后的区间结果。
    ④使用变量 pre 存储当前合并的区间,初始值设为排序后的第一个区间 intervals[0]。
    ⑤遍历排序后的区间数组,从第二个区间开始:
    (1)如果当前区间的起始位置小于等于 pre 区间的结束位置,说明两个区间可以合并,更新 pre 区间的结束位置为两者结束位置的较大值。
    (2)如果当前区间的起始位置大于 pre 区间的结束位置,说明无法合并,将当前的 pre 区间加入到结果集中,并更新 pre 为当前区间。
    ⑥最后将最后一个 pre 区间加入结果集中,并将结果集转换成数组形式返回。

三、代码示例:

//时间复杂度为 O(nlogn)
class Solution {
    public int[][] merge(int[][] intervals) {
        // 如果只有一个区间,直接返回
        if(intervals.length == 1) return intervals;
        
        // 创建一个链表用于存储合并后的区间
        LinkedList<int[]> result = new LinkedList<>();
        
        // 按照区间的左端点进行排序
        Arrays.sort(intervals, (a, b)-> {
            return a[0] - b[0];
        });
        
        // 初始化pre为第一个区间
        int[] pre = intervals[0];
        
        // 遍历排序后的区间数组
        for(int i = 1; i < intervals.length; i++){
            // 如果需要合并当前区间与pre
            if(pre[1] >= intervals[i][0]){
                pre[1] = Math.max(pre[1], intervals[i][1]); // 合并后的右端点取二者的最大值
            }
            else{
                result.add(pre); // 否则,将pre加入结果
                pre = intervals[i]; // 更新pre为当前区间
            }          
        }
        
        result.add(pre); // 将最后一个pre加入结果
        
        // 转换为二维数组并返回
        return result.toArray(new int[result.size()][]);
    }
}
  • 进一步简洁代码:在遍历过程中,只需判断当前区间与 merged 数组中最后一个区间的关系,从而决定是添加新区间还是合并区间。使用 ArrayList 替代 LinkedList,ArrayList 在访问元素时速度更快,适合用于按顺序访问和动态添加元素的场景。
class Solution {
    public int[][] merge(int[][] intervals) {
        // 按照区间的左端点进行排序
        Arrays.sort(intervals, (a, b)-> {
            return a[0] - b[0];
        });
        
        List<int[]> merged = new ArrayList<>();
        
        for (int i = 0; i < intervals.length; i++) {
            // 如果 merged 数组为空或当前区间的左端点大于 merged 数组中最后一个区间的右端点
            if (merged.isEmpty() || intervals[i][0] > merged.get(merged.size() - 1)[1]) {
                merged.add(intervals[i]);
            } else {
                // 更新 merged 数组中最后一个区间的右端点为当前区间右端点和 merged 数组中最后一个区间右端点的最大值
                merged.get(merged.size() - 1)[1] = Math.max(intervals[i][1], merged.get(merged.size() - 1)[1]);
            }
        }
        
        return merged.toArray(new int[merged.size()][]);
    }
}
  • 时间复杂度分析:在这个方法中,我们首先对输入数组进行排序,时间复杂度为 O(nlogn),其中 n 是输入数组 intervals 的长度。接着,我们遍历排序后的数组一次,对每个区间进行处理。因为数组已经排序,所以只需线性地遍历一次即可完成合并操作。

四、补充与总结:

  1. 二维数组排序
    对二维数组进行排序时,通常需要自定义比较规则,因为默认情况下 Java 中的排序方法并不直接支持对二维数组的排序。在使用 Arrays.sort() 方法对二维数组进行排序时,需要通过提供一个比较器(Comparator)来定义元素之间的比较方式。
    对于二维数组,比较器可以通过 lambda 表达式或传统的 Comparator 实现类来定义。在比较器中,可以指定按照二维数组的某一列或某些列进行排序,也可以根据特定的比较逻辑来定义排序规则。
//左端点升序排序
Arrays.sort(intervals, (a, b) -> {
    return a[0] - b[0];
});
//左端点降序排序
Arrays.sort(intervals, (a, b) -> {
    return b[0] - a[0];
});
//右端点升序排序
Arrays.sort(intervals, (a, b) -> {
    return a[1] - b[1];
});
//右端点降序排序
Arrays.sort(intervals, (a, b) -> {
    return b[1] - a[1];
});
  1. Lambda 表达式是什么?
    Java 8 中引入的一种新特性,用于简化匿名内部类的语法。Lambda 表达式可以看作是一个匿名函数,它允许你直接以内联的方式为函数式接口(Functional Interface)提供实现。Lambda 表达式的语法形式如下:
    (parameters) -> expression

    (parameters) -> { statements; }
    ①parameters 指定了 Lambda 表达式的参数列表。
    ②-> 是 Lambda 运算符,将参数列表和 Lambda 表达式的主体分开。
    ③expression 或 { statements; } 定义了 Lambda 表达式的主体,可以是一个表达式或一段代码块。

  2. result.toArray(new int[result.size()][])
    这行代码的作用是将 result 这个 LinkedList 转换为二维数组。
    具体来说,result.toArray(new int[result.size()][]) 这段代码中:
    ①result.size() 返回了 result 中元素的个数。
    ②new int[result.size()][] 创建了一个新的二维数组,第一维的长度为 result.size()。
    ③result.toArray(new int[result.size()][]) 将 result 中的元素复制到新创建的二维数组中。
    ④最终的效果是将 LinkedList 转换为二维数组,以便返回合并后的区间数组。

  • 19
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
回答: 递归求解二维数组路径可以使用暴力递归的方式。思路是,对于二维数组中的每一个点,记录其到终点(右下角点)的最小路径和。具体做法是,分别查看该点的正下方和右边两个点的值,选择其中较小的一个与数组原位置的值相加。最终,数组左上角位置的值即为问题的解。\[1\] #### 引用[.reference_title] - *1* [二维数组从左上到右下,返回最小路径和问题的解法](https://blog.csdn.net/z1171127310/article/details/127716640)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [LeetCode题目总结——二维数组](https://blog.csdn.net/weixin_40131652/article/details/108680706)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [二维数组的最小路径和问题](https://blog.csdn.net/hotonyhui/article/details/126962888)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值