java---贪心---区间覆盖(每日一道算法2022.10.29)

题目:
给定 N 个闭区间 [ai,bi] 以及一个线段区间 [s,t],请你选择尽量少的区间,将指定线段区间完全覆盖
输出最少区间数,如果无法完全覆盖则输出 −1

第一行包含两个整数 s 和 t,表示给定线段区间的两个端点。
第二行包含整数 N,表示给定区间数。
接下来 N 行,每行包含两个整数 ai,bi,表示一个区间的两个端点。

输出一个整数,表示所需最少区间数。

如果无解,则输出 −1。

1 ≤ N ≤ 10e5,
−10e9 ≤ ai ≤ bi ≤ 10e9
−10e9 ≤ s ≤ t ≤ 10e9

输入:
1 5
3
-1 3
2 4
3 5
输出:
2
public class 区间覆盖 {
    public static int N = 1000010, INF = -2000000009, n, start, end;
    public static Range[] all = new Range[N];

    public static void main(String[] args) {
        //读入
        Scanner in = new Scanner(System.in);
        start = in.nextInt(); end = in.nextInt();
        n = in.nextInt();
        for (int i = 0; i<n; i++) {
            int l = in.nextInt(), r = in.nextInt();
            all[i] = new Range(l, r);
        }

        //根据区间的左端点的值,从小到大sort(这里偷懒用了lambda重写比较,直接在Range中重写compareTo也可以)
        Arrays.sort(all, 0, n, ((o1, o2) -> o1.l - o2.l));

        //res记录区间数量,success判断算法是否成功得到正确结果
        int res = 0;
        boolean success = false;
        for (int i = 0; i<n; i++) {
            //双指针,j为区间,r为最大右端点值
            //拿到剩下的区间中,左端点和start有交集(确保覆盖start >= all[j].l),同时右端点最大的区间(说明这个区间在可选区间中最长,Max(r))
            int j = i, r = INF;
            while (j < n && start >= all[j].l) {
                r = Math.max(r, all[j].r);
                j++;
            }

            //如果当前起始点大于可选区间的最大右端点,说明区间之间有缝隙,无法完全覆盖
            if (start > r) break;

            res++;  //记得更新区间数量

            //如果r已经大于目标区间的end点了,那么说明找到答案了,退出循环即可
            if (r >= end) {
                success = true;
                break;
            }

            //start更新为最大右端点,这里注意下,i是更新为j-1,因为j最后一次通过while的条件后,还多++了一次
            start = r;
            i = j - 1;
        }

        if (success) System.out.println(res);
        else System.out.println("-1");
    }
}

//定义一个区间类,l表示左端点,r表示右端点
class Range{
    int l, r;
    public Range(int l, int r) {
        this.l = l; this.r = r;
    }
}

思路:
1.将所有区间按照左端点大小,从小到大排序
2.枚举每个区间,在所有能覆盖start的区间中(区间左端点和start有交集,start >= all[ j ].L),选择右端点最大的区间(说明这个区间在可选区间中覆盖最长),将start更新为这个右端点值

以题目为栗子:
目标区间start和end是1 5
根据左端点排序从小到大排序
首先拿到-1 3这个区间,符合start >= -1, 将start更新为3,区间数量+1
接下来有两个区间可以选择,2 4或者3 5,2和3都小于等于start,然后我们取右端点最大的选择,也就是3 5这个区间,将start更新为5,区间数量+1
这时start已经大于等于5,算法结束,输出区间数量为2
请添加图片描述

声明:
算法思路来源为y总,详细请见https://www.acwing.com/
本文仅用作学习记录和交流

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值