数据结构和算法:合并区间

本文介绍了LeetCode上的区间合并问题,提供了C++解决方案,包括对输入区间排序并逐一判断合并的方法,以及利用有序关联容器自动排序的方法。详细解释了算法思路和测试用例,适合编程爱好者练习和讨论。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内卷之源:

https://leetcode.cn/problems/merge-intervals/

https://leetcode.cn/problems/SsGoHC/

https://www.nowcoder.com/practice

题目描述:

 * 以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi]
 * 请合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间
 * 保证合并后的区间按区间起点升序排列。

 * 说明:
     1 <= intervals.length <= 10^4
     intervals[i].length == 2
     0 <= starti <= endi <= 10^4

测试用例:

InputOutput

intervals = [[1,9],[2,5],[19,20],[10,11],[12,20],[0,3],[0,1],[0,2]]

[[0,9],[10,11],[12,20]]

解释:区间 [0,3],[0,1],[0,2],[1,9]和[2,5] 重叠,可合并为 [0,9] ; 区间 [19,20] 和 [12,20] 重叠,可合并为 [12,20] 

intervals = [[1,3],[2,6],[8,10],[15,18]]

[[1,6],[8,10],[15,18]]

解释:区间 [1,3] 和 [2,6] 重叠, 将它们合并为 [1,6]

intervals = [[10,30],[20,60],[80,100],[150,180]][[10,60],[80,100],[150,180]]
intervals = [[1,4],[4,5]][[1,5]]
intervals = [[3,6]][[3,6]]

思路分析:

 *   本题明显要进行大小比较。而输入是多个区间的集合,所以实际是对各区间的端点进行大小比较。
 *   如果不考虑区间的排列顺序,以离散顺序进行比较,会存在重复运算。
 *   因此先对区间进行排序 —— 比较各区间左端点(没必要同时比较左、右端点)。
 *   按从前往后的顺序,依次判断相邻区间是否存在重叠区域:(若用下一个区间的右端点与上一个区间的右端点比较,则是有三种情况)
         (1)如果下一个区间的左端点大于上一个区间的右端点,则两区间必不重合
         (2)如果下一个区间的左端点不大于上一个区间的右端点,则两区间有重合区域,新区间的左端点为上一个区间的左端点,新区间的右端点为两区间右端点最大值

编程实现(C++):

/*
 ************************************************************
 * @author    SLF
 * @version	  V1.0.0
 * @date      22-May-2021
 ************************************************************
 */

#include <iostream>
#include <vector>
#include <map>
#include <unordered_map>
#include <algorithm>

using namespace::std;

class Solution {
public:
    Solution() {}
    ~Solution() {}

	/*
	 * 对输入手动排序
	 */
    vector<vector<int>> merge(vector<vector<int>>& intervals)
    {
        vector<vector<int>> out;
        const int n = intervals.size();

        if(!n)
        {//不应在for循环中多次检查 out.empty()
            return out;
        }

        sort(intervals.begin(), intervals.end()); //左端点相同时会继续判断右端点,实际没必要
		
        out.push_back(intervals[0]);
        for(int i = 1; n > i; ++i)
        {
            if(out.back()[1] < intervals[i][0])
            {//经排序后,下一个区间的左端点大于上一个区间的右端点,则两区间不重合
                out.push_back(intervals[i]);
            }
            else
            {//经排序后,下一个区间的左端点不大于上一个区间的右端点,则两区间重合,更新合并区间的右端点
                out.back()[1] = max(out.back()[1], intervals[i][1]);
            }
        }

        return out;
    }
	
	/*
	 * 使用有序关联容器对输入自动排序
	 */
    // unordered_map<int, int> merge_sorted(multimap<int, int>& intervals)
    vector<vector<int>> merge_sorted(multimap<int, int>& intervals)
    {
        // unordered_map<int, int> out; //输入有序,输出必然有序,所以没必要再定义一个有序容器  //但最终需要打印输出,而无序容器元素存储顺序并不是按照写入顺序
        vector<vector<int>> out;
        const int n = intervals.size();

        if(!n)
        {//不应在for循环中多次检查 out.empty()
            return out;
        }
        
        //可重复关键字的关联容器不允许下标访问,使用迭代器
        auto iter = intervals.cbegin();
        out.push_back({iter->first, iter->second});
        while(intervals.cend() != (++iter))
        {
            if(out.back()[1] < iter->first)
            {//经排序后,下一个区间的左端点大于上一个区间的右端点,则两区间不重合
                out.push_back({iter->first, iter->second});
            }
            else
            {//经排序后,下一个区间的左端点不大于上一个区间的右端点,则两区间重合,更新合并区间的右端点
                out.back()[1] = max(out.back()[1], iter->second);
            }
        }

        return out;
    }
};

int main(void)
{
    //每个区间两个端点元素,每个端点元素取值0~10000,故数据类型实际可用unsigned short
    vector<multimap<int, int>> intervals_sorted = {{{1,9}, {2,5}, {19,20}, {10,11}, {12,20}, {0,3}, {0,1}, {0,2}}, {{10,30},{20,60},{80,100},{150,180}}, {{1,3},{2,6},{8,10},{15,18}}, {{1,4},{4,5}}, {{3,6}}}; //关联式容器虽拥有自动排序功能,但是每安插一个新元素就进行一次排序,所以速度并不及序列式容器经常采用的手法:先安插元素,再统一排序
    vector<vector<vector<int>>> intervals = {{{1,9}, {2,5}, {19,20}, {10,11}, {12,20}, {0,3}, {0,1}, {0,2}}, {{10,30},{20,60},{80,100},{150,180}}, {{1,3},{2,6},{8,10},{15,18}}, {{1,4},{4,5}}, {{3,6}}};
    vector<vector<int>> out;
    Solution sl;

    const int n = intervals.size();
    for(int i = 0; n > i; ++i)
    {
        out = sl.merge_sorted(intervals_sorted[i]);
        for(const auto d : out)
        {
            cout << d[0] << ',' << d[1] << endl;
        }
        cout << endl;

        out = sl.merge(intervals[i]);
        for(const auto d : out)
        {
            cout << d[0] << ',' << d[1] << endl;
        }
        cout << endl;
    }

    return 0;
}

  

郑重提示:①解题思路非最优,覆盖条件可能不全,仅供练习参考。

                  ②若有更佳思路或疑问,可在评论区留言相互讨论,不亦乐乎。

                  ③本文不允许转载,若认可本文,可点赞收藏关注。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值