题目:
给定 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/
本文仅用作学习记录和交流