• 区间贪心问题合集


    区间贪心问题

    LeetCode 56. 合并区间

    以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。

    两个区间能够重叠,当且仅当:区间B的start小于等于区间A的end。

    设ABC三个区间分别为[startA, endA]、[startB, endB]、[startC, endC],假设A与B能合并,与C不能合并,则:

    startB <= endA,startC > endB >= startB

    因此startA、startB、startC满足:startA < startB < startC或startB < startA < startC,换个角度考虑,能够合并的区间,它们的起始点start必然是相邻的。

    因此,可以将所有区间按照start进行排序,并贪心地合并相邻区间即可。

    vector> merge(vector>& intervals) 
    {
        sort(intervals.begin(), intervals.end());
        vector> res;
        int x = -1;
        int y = -1;
        for (auto& interval : intervals)
        {
            if (x == -1 && y == -1)
            {
                x = interval[0];
                y = interval[1];
                continue;
            }
            if (interval[0] <= y) // 当前区间与前一个区间重合,此时更新前一个区间的end
            {
            	y = max(interval[1], y);
            }
            else // 区间不重合,将前一个区间插入结果集,同时更新前一个区间为当前区间
            {
                res.push_back({x, y});
                x = interval[0];
                y = interval[1];
            }
        }
        res.push_back({x, y});
        return res;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    LeetCode 57. 插入区间

    给你一个 无重叠的 ,按照区间起始端点排序的区间列表。

    在列表中插入一个新的区间,你需要确保列表中的区间仍然有序且不重叠(如果有必要的话,可以合并区间)。

    由于区间已经排序好,因此只需要初始化前一个区间为待插入的区间,并顺序遍历,尝试使用该区间合并其他区间。

    vector> insert(vector>& intervals, vector& newInterval) 
    {
        int n = intervals.size();
        vector> res;
        int x = newInterval[0];
        int y = newInterval[1]; 
        for (int i = 0; i < n; ++i)
        {
            if (intervals[i][0] > y) // 找到了插入点,此时更新待插入的区间
            {
                res.push_back({x, y});
                x = intervals[i][0];
                y = intervals[i][1];
            }
            else if (intervals[i][1] < x) // 还没有找到合适的插入区间
            {
                res.push_back(intervals[i]);
            }
            else // 区间可合并
            {
                x = min(x, intervals[i][0]);
                y = max(y, intervals[i][1]);
            }
        }
        res.push_back({x, y});
        return res;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    LeetCode 435. 无重叠区间

    给定一个区间的集合 intervals ,其中 intervals[i] = [starti, endi] 。

    返回 需要移除区间的最小数量,使剩余区间互不重叠 。

    区间A与区间B重叠,当且仅当startB

    我们将区间按照start进行升序排列。当区间重叠时,此时需要移除的区间必然是end值较大的那一个区间,因为这样能够尽可能地减少当前区间与剩余区间重叠的可能性。

    具体算法为:记录上一个区间的preend,然后遍历所有区间。

    • 当发生重叠时,选择end值较小的那一个更新preend,同时res++。
    • 没有重叠时,只需动态更新preend为当前已选区间的end最大值即可,不需要res++。
    • 最后res的值就是移除区间的最小数量。
    int eraseOverlapIntervals(vector>& intervals) 
    {
        sort(intervals.begin(), intervals.end());
        int y = intervals[0][1];
        int res = 0;
        for (int i = 1; i < intervals.size(); ++i)
        {
            // 重叠
            if (intervals[i][0] < y)
            {
                ++res;
                y = min(intervals[i][1], y);
            }
            else
            {
                y = max(intervals[i][1], y);
            }
        }
        return res;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    LeetCode 2406. 将区间分为最少组数

    给你一个二维整数数组 intervals ,其中 intervals[i] = [lefti, righti] 表示闭区间[lefti, righti] 。

    你需要将 intervals 划分为一个或者多个区间组,每个区间只属于一个组,且同一个组中任意两个区间不相交 。

    请你返回最少需要划分成多少个组。

    如果两个区间覆盖的范围有重叠(即至少有一个公共数字),那么我们称这两个区间是相交的。比方说区间 [1, 5] 和 [5, 8] 相交。

    如果区间B的start小于等于区间A的end,则A与B能合并,即它们不能在同一组。

    因此,我们维护每一个分组的最大end的小根堆:

    • 如果intervals[i]的start小于等于堆顶元素,则表明它的start小于等于当前分组内任意一个分组的最大end,因此该区间只能单独成一组。
    • 如果intervals[i]的start大于堆顶元素,则该区间至少可以添加至堆顶这个分组,因此更新这个分组的最大end为intervals[i]的end即可。

    最终,堆中元素的数量就是组数。

    int minGroups(vector>& intervals) 
    {
        sort(intervals.begin(), intervals.end());
        priority_queue, greater> end;
        for (auto& interval : intervals)
        {
            if (!end.empty() && interval[0] > end.top())
            	end.pop();
            end.push(interval[1]);
        }
        return end.size();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    后端知识语言算法复习笔记
    风辞远的科技茶屋:可怖的AI
    数据结构与算法-插入&希尔&归并
    使用docker部署一个jar项目
    怎么转换音频格式?建议收藏这几个方法
    Controller接收Postman的raw参数时,属性值全部为空
    Ubuntu安装AdGuardhome(树莓派安装AdGuardhome)
    整理MyBatis
    发布、部署,傻傻分不清楚?从概念到实际场景,再到工具应用,一篇文章让你彻底搞清楚
    【PID优化】基于人工蜂群算法PID控制器优化设计含Matlab源码
  • 原文地址:https://blog.csdn.net/Wyf_Fj/article/details/126818481