






















[s, t] 和 N 个闭区间,选择最少数量的区间完全覆盖目标线段,无法覆盖则输出 -1。1 ≤ N ≤ 10^5,区间端点可取值范围 [-10^9, 10^9]。按左端点排序后,每次在能覆盖当前起点的区间中,选择右端点最大的区间,最大化覆盖范围,从而最小化区间使用数量。
AcWing 907 “区间覆盖”问题(即:用最少的给定区间完全覆盖目标区间 [s, t])在 Java 中的经典实现如下。该解法采用贪心策略 + 双指针,时间复杂度为 O(n log n)(主要来自排序)。
[s, t][a_i, b_i][s, t] 所需的最少区间数-1import java.util.*;
public class Main {
static class Interval {
int l, r;
Interval(int l, int r) {
this.l = l;
this.r = r;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int s = sc.nextInt();
int t = sc.nextInt();
int n = sc.nextInt();
Interval[] intervals = new Interval[n];
for (int i = 0; i < n; i++) {
int a = sc.nextInt();
int b = sc.nextInt();
intervals[i] = new Interval(a, b);
}
// 按左端点升序排序
Arrays.sort(intervals, (o1, o2) -> Integer.compare(o1.l, o2.l));
int res = 0; // 使用的区间数量
int currentEnd = s; // 当前已覆盖到的位置
int i = 0; // 遍历指针
while (currentEnd < t) {
int maxRight = currentEnd; // 在能覆盖 currentEnd 的区间中找最远右端点
// 找所有左端点 <= currentEnd 的区间,并记录最大右端点
while (i < n && intervals[i].l <= currentEnd) {
if (intervals[i].r > maxRight) {
maxRight = intervals[i].r;
}
i++;
}
// 如果无法向右扩展,说明覆盖失败
if (maxRight == currentEnd) {
System.out.println(-1);
return;
}
// 选择这个最远的区间
res++;
currentEnd = maxRight; // 更新已覆盖的右边界
}
System.out.println(res);
}
}
l 升序排列,确保我们从左到右处理。currentEnd(初始为 s)。l <= currentEnd 的区间中,选择 r 最大的那个(即延伸最远)。maxRight 没有超过 currentEnd,说明出现“空隙”,无法继续覆盖。currentEnd >= t 时,成功覆盖目标区间。输入:
1 5
3
-1 3
2 4
3 5
执行过程:
[-1,3], [2,4], [3,5]currentEnd=1,可选 [-1,3] → maxRight=3 → res=1currentEnd=3,可选 [2,4], [3,5] → maxRight=5 → res=25 >= 5,结束,输出 2✅ 输出:2
l <= currentEnd 是合法的。i++ 的推进逻辑,否则会死循环。类似题目:https://leetcode.cn/problems/video-stitching/submissions/679961490/
class Solution {
class Interval{
private int l;
private int r;
public Interval(int l, int r) {
this.l = l;
this.r = r;
}
}
public int videoStitching(int[][] clips, int t) {
int n = clips.length;
Interval[] intervals = new Interval[n];
for (int i = 0; i < n; i++) {
intervals[i]=new Interval(clips[i][0],clips[i][1]);
}
// 按左端点升序排序
Arrays.sort(intervals, Comparator.comparingInt(o -> o.l));
int res = 0; // 使用的区间数量
int currentEnd = 0; // 当前已覆盖到的位置
int i = 0; // 遍历指针
while (currentEnd < t) {
int maxRight = currentEnd; // 在能覆盖 currentEnd 的区间中找最远右端点
// 找所有左端点 <= currentEnd 的区间,并记录最大右端点
while (i < n && intervals[i].l <= currentEnd) {
if (intervals[i].r > maxRight) {
maxRight = intervals[i].r;
}
i++;
}
// 如果无法向右扩展,说明覆盖失败
if (maxRight == currentEnd) {
return -1;
}
// 选择这个最远的区间
res++;
currentEnd = maxRight; // 更新已覆盖的右边界
}
return res;
}
}
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。