leetcode:1288. 删除被覆盖区间

题目

给你一个区间列表,请你删除列表中被其他区间所覆盖的区间。
只有当 c <= ab <= d 时,我们才认为区间 [a,b) 被区间 [c,d) 覆盖。
在完成所有删除操作后,请你返回列表中剩余区间的数目。

示例:

  1. 输入:intervals = [[1,4],[3,6],[2,8]]
  2. 输出:2
  3. 解释:区间 [3,6] 被区间 [2,8] 覆盖,所以它被删除了。

解答 & 代码

区间问题的两个技巧

  1. 排序:常见的排序方法就是按照区间起点排序,或者先按照起点升序排序,若起点相同,则按照终点降序排序。
  • 本题就是先按照区间起点升序排序,若区间起点相同,则按照区间终点降序排序
  1. 画图:画出两个区间所有可能的相对位置,分情况讨论(下图的 case 2、3 可以合并,都是不能覆盖)

image.png

另,C++ sort 自定义排序规则的写法见下面代码:

class Solution {
private:
    // 自定义排序规则:按照区间起点升序排序,若区间起点相同,则按区间终点降序排序
    static bool cmp(vector<int> a, vector<int> b)
    {
        return a[0] < b[0] || (a[0] == b[0] && a[1] > b[1]);
    }
public:
    int removeCoveredIntervals(vector<vector<int>>& intervals) {
        // 1. 排序:按照区间起点升序排序,若区间起点相同,则按区间终点降序排序
        sort(intervals.begin(), intervals.end(), cmp);

        int left = intervals[0][0];
        int right = intervals[0][1];
        int result = 0;        // 统计可以被覆盖的区间数
        for(int i = 1; i < intervals.size(); ++i)
        {
            vector<int> curInterval = intervals[i];
            // case1:如果当前区间被 [left, right] 覆盖,则 result 计数+1
            if(right >= curInterval[1])
                ++result;
            // case2 / 3:如果当前区间和 [left, right] 相交/无交集,则当前区间不能被覆盖
            // 用当前区间替换 [left, right]
            else if(right < curInterval[1])
            {
                left = curInterval[0];
                right = curInterval[1];
            }
        }
        // 原区间数 - 被覆盖的区间数,即剩余区间数
        return intervals.size() - result;
    }
};

复杂度分析:设有 N 个区间

  • 时间复杂度 O(N log N):排序的时间复杂度
  • 空间复杂度 O(1):

执行结果:

执行结果:通过

执行用时:104 ms, 在所有 C++ 提交中击败了 10.54% 的用户
内存消耗:28.8 MB, 在所有 C++ 提交中击败了 4.99% 的用户