【基础算法】区间覆盖问题

484 阅读3分钟

🌹作者:云小逸
📝个人主页:云小逸的主页
📝Github:云小逸的Github
🤟motto:要敢于一个人默默的面对自己,==强大自己才是核心==。不要等到什么都没有了,才下定决心去做。种一颗树,最好的时间是十年前,其次就是现在!学会自己和解,与过去和解,努力爱自己。==希望春天来之前,我们一起面朝大海,春暖花开!==🤟 👏专栏:C++👏 👏专栏:Java语言👏👏专栏:Linux学习👏
👏专栏:C语言初阶👏👏专栏:数据结构👏👏专栏:备战蓝桥杯👏

@TOC


前言

今天我们继续学习算法,加油。这篇文章写的是区间分组问题,使用了贪心思想。希望这篇可以有幸帮助到你,码字不易,请多多支持。 在这里插入图片描述

——————————————————————————————

区间覆盖问题

给定 NN 个闭区间 [ai,bi][a_i,b_i] 和一个线段区间 [s,t][s,t],求最少需要选择多少个闭区间,才能将线段区间完全覆盖。如果无法完全覆盖则输出-1。

输入格式

第一行包含两个整数 sstt,表示线段区间的两个端点。

第二行包含整数 NN,表示给定区间数。

接下来 NN 行,每行包含两个整数 aia_ibib_i,表示一个区间的两个端点。

输出格式

输出一个整数,表示所需最少区间数。如果无解,则输出-1。

数据范围

1N1051\le N\le10^5109aibi109-10^9\le a_i\le b_i\le 10^9109st109-10^9\le s\le t\le 10^9

输入样例

1 5
3
-1 3
2 4
3 5

输出样例

2

解题思路

由于要将线段区间完全覆盖,因此我们可以按照区间的右端点从小到大排序,然后依次选择右端点尽量小且与已选择的区间不重叠的区间,直到所有区间都被覆盖为止。

在选择区间时,我们可以用一个指针 pp 记录当前右端点最小的区间,用一个变量 resres 记录已选择的区间数,每次选择一个与 [s,t][s,t] 相交且右端点最小的区间 [ak,bk][a_k,b_k],更新指针 pp,并将 resres 加1。

如果在选择过程中存在无法覆盖 [s,t][s,t] 的情况,则说明无解。

C++代码:

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e5 + 10;
int n;
struct Range {
    int l, r;
    bool operator < (const Range &t) const {
        return r < t.r;
    }
}range[N];

int main()
{
    int s, t;
    cin >> s >> t >> n;
    for (int i = 0; i < n; i ++ ) cin >> range[i].l >> range[i].r;
    sort(range, range + n); //将区间按照右端点从小到大排序

    int p = s, res = 0; // p 表示最后一个被选中的区间的右端点,初始化为 s
    for (int i = 0; i < n && p < t; i ++ ) //只要 p < t,就需要选择一个新的区间
        if (range[i].l <= p + 1) // 如果区间的左端点小于等于 p+1,说明可以覆盖 [p+1, r]
            p = max(p, range[i].r), res ++; // 选择右端点最大的区间

    if (p < t) puts("-1"); // 如果最后 p 还小于 t,说明无法覆盖 [s, t]
    else printf("%d\n", res);
    return 0;
}

时间复杂度

排序的时间复杂度为 O(NlogN)O(N\log N),选取区间的时间复杂度为 O(N)O(N),因此总时间复杂度为 O(NlogN)O(N\log N)

最后

十分感谢你可以耐着性子把它读完和我可以坚持写到这里,送几句话,对你,也对我:

1.把时间尺度拉长,拉长十年看当下

2.不说负面情绪,只描述事实;

3.越专注于过好自己,能量和幸运越会照顾你; 只解决问题,不做没有意义的担心,输了就认;

4.学会原谅自己,要允许自己做错事,允许自己出现情绪波动,我知道你已经很努力很努力在做好了

5.所有你害怕的、想逃避的事情,最终都要面对,既然这样不如选择坦然面对。即使结果不如人愿,没关系,至少这个过程是享受的,而不是一路带着恐惧和害怕。

最后如果觉得我写的还不错,请不要忘记==点赞==✌,==收藏==✌,加==关注==✌哦(。・ω・。)

愿我们一起加油,奔向更美好的未来,愿我们从懵懵懂懂的一枚==菜鸟==逐渐成为==大佬==。加油,为自己点赞!