leetcode_56 合并区间

发布于:2025-06-10 ⋅ 阅读:(20) ⋅ 点赞:(0)

1. 题意

给一个区间集合,求对有交集合的区间合并后的区间。

2. 题解

2.1 排序+双指针

为什么需要对数据进行排序,
为什么是对区间起点进行排序?
对区间终点进行排序行不行?

实际上对于两个区间 [ l 1 , r 1 ]   [ l 2 , r 2 ] [l_1,r_1]\ [l_2,r_2] [l1,r1] [l2,r2], 我们只需要他们满足
l 1 ≤ r 2 , l 2 ≤ r 1 l_1 \le r_2, l_2 \le r_1 l1r2,l2r1
两个条件即可。

而无论是按照区间的起点,还是按照区间的终点进行排序。 我们都是在保证其中一个条件。

如果按区间左端点排序,它保证 l 1 ≤ l 2 ∧ l 2 ≤ r 2 ⇒ l 1 ≤ r 2 l_1 \le l_2 \land l_2 \le r_2\Rightarrow l_1 \le r_2 l1l2l2r2l1r2
如果按区间右端点排序,它保证了 r 1 ≤ r 2 ∧ l 1 ≤ r 1 ⇒ l 1 ≤ r 2 r_1 \le r_2 \land l_1 \le r_1 \Rightarrow l_1 \le r_2 r1r2l1r1l1r2

再谈官解里面的正确性证明;为什么存在 a [ i ] , a [ k ] a[i], a[k] a[i],a[k]本应该合并,一定会存在三元组 i , j , k ( i < j < k ) i,j,k(i <j <k) i,j,k(i<j<k), 满足 a [ i ] , a [ j ] a[i],a[j] a[i],a[j]不能合并,且 a [ j ] , a [ k ] a[j],a[k] a[j],a[k]不能合并。

首先 i , k i,k i,k肯定是不相邻的,如果相邻的话就不是异常情况了,所以 i , k i,k i,k之间存在其他整数;

其次为什么一定是 a [ i ] , a [ j ] a[i],a[j] a[i],a[j]不能合并且 a [ j ] , a [ k ] a[j],a[k] a[j],a[k]也不能合并。

因为 a [ i ] , a [ j ] a[i],a[j] a[i],a[j]合并后一定是包含 a [ i ] a[i] a[i],因此必然可以和 a [ k ] a[k] a[k]合并的;
同理 a [ j ] , a [ k ] a[j],a[k] a[j],a[k]合并后一定是包含 a [ k ] a[k] a[k], 因此必然可以和 a [ i ] a[i] a[i]合并的。

因此 a [ j ] a[j] a[j] a [ i ] , a [ k ] a[i],a[k] a[i],a[k]都不能合并。

因此必有
a [ i ] . r < a [ j ] . l a [ j ] . r < a [ k ] . l a[i].r < a[j].l\\ a[j].r <a[k].l a[i].r<a[j].la[j].r<a[k].l
进而
a [ j ] . l < a [ j ] . r a [ i ] . r < a [ k ] . l a[j].l < a[j].r\\ a[i].r < a[k].l a[j].l<a[j].ra[i].r<a[k].l
这与 a [ i ] , a [ k ] a[i],a[k] a[i],a[k]相交
a [ i ] . r ≥ a [ k ] . l a[i].r \ge a[k].l a[i].ra[k].l
矛盾。

按右端点排序时,我们需要反着来处理。

因为正序无法处理[1,2] [3,5] [2,6]这样的情况。

  • 按左端点排序
class Solution {
public:


    vector<vector<int>> merge(vector<vector<int>>& intervals) {

        sort( intervals.begin(), intervals.end(), [](const std::vector<int> &a, const std::vector<int> &b)
        {
            if ( a[0] != b[0])
                return a[0] < b[0];
            return a[1] < b[1];
        });

        for ( auto it = intervals.begin(); it != intervals.end(); ) {
            
            auto lst = it + 1;  
            while (lst != intervals.end() && (*lst)[0] <= (*it)[1] ) {
                (*it)[1] = std::max((*it)[1], (*lst)[1]);
                ++lst;
            }

            if (lst != it + 1) {
                it = intervals.erase( it + 1, lst);
            }
            else {
                ++it;
            }
        }

        return intervals;
    }
};
  • 按右端点排序
class Solution {
public:


    vector<vector<int>> merge(vector<vector<int>>& intervals) {
        
        sort( intervals.begin(), intervals.end(),[](const std::vector<int> &a,
            const std::vector<int> &b){
            if ( a[1] != b[1]) {
                return a[1] < b[1];
            }
            return a[0] < b[0];
        });

        std::vector<std::vector<int>> ans;

        int sz = intervals.size();
        int cur = 0;
        int lst{0};
        for (int i = intervals.size() - 1;i > -1; i = lst) {
            cur = i;
            lst = i - 1;

            while ( lst > -1 && intervals[cur][0] <= intervals[lst][1]) {
                intervals[cur][0] = std::min( intervals[cur][0], intervals[lst][0]);
                --lst;
            }
            ans.insert( ans.begin(), intervals[cur]); 
        }

        return ans;
    }
};
2.2 差分数组

使用差分数组标记来处理一整片,当出现连续的正数的时候说明是一整个区间。

但有个问题是,似乎无法处理 [ 1 , 2 ] [ 3 , 4 ] [1,2][3,4] [1,2][3,4]这样的情况;

灵之一手的是,直接把区间给扩大到原来两倍,这样不相交区间之间的距离最少就成2了,上面那种情况就不会出现了。

实在是妙!

class Solution {
public:


    vector<vector<int>> merge(vector<vector<int>>& intervals) {

        vector<int> diff(2e4+4, 0);

        int mx = 0;
        for (auto ints: intervals) {
            diff[ 2 * ints[0] ]++;
            diff[ 2 * ints[1] + 1]--;
            mx = std::max(mx, ints[1]);
        }

        int cur = 0;

        vector< vector<int>> ans;

        vector<int> tmp(2, 0);
        for (int i = 0;i <= 2 * mx + 1; ++i) {
            if ( cur == 0 && diff[i] > 0) {
                tmp[0] = i / 2;
            }
            else if (cur > 0 && (diff[i] + cur == 0) ) {
                tmp[1] = (i - 1) / 2;
                ans.push_back( tmp);
            }
            cur += diff[ i ];
        }

        return ans;
    }
};

参考

leetcode-官解
03xf的题解