惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

酷 壳 – CoolShell
酷 壳 – CoolShell
H
Hacker News: Front Page
P
Palo Alto Networks Blog
T
ThreatConnect
Apple Machine Learning Research
Apple Machine Learning Research
博客园_首页
T
True Tiger Recordings
P
Privacy & Cybersecurity Law Blog
B
Blog
IT之家
IT之家
Last Week in AI
Last Week in AI
F
Full Disclosure
Hacker News: Ask HN
Hacker News: Ask HN
C
Comments on: Blog
Microsoft Azure Blog
Microsoft Azure Blog
C
Cybersecurity and Infrastructure Security Agency CISA
Microsoft Security Blog
Microsoft Security Blog
博客园 - 【当耐特】
N
News and Events Feed by Topic
NISL@THU
NISL@THU
腾讯CDC
雷峰网
雷峰网
Security Latest
Security Latest
李成银的技术随笔
M
Microsoft Research Blog - Microsoft Research
L
LangChain Blog
L
Lohrmann on Cybersecurity
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
C
Check Point Blog
Y
Y Combinator Blog
Recent Announcements
Recent Announcements
博客园 - Franky
N
News | PayPal Newsroom
V
V2EX
A
About on SuperTechFans
The Register - Security
The Register - Security
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Google Online Security Blog
Google Online Security Blog
MyScale Blog
MyScale Blog
Cisco Talos Blog
Cisco Talos Blog
Vercel News
Vercel News
WordPress大学
WordPress大学
C
Cyber Attacks, Cyber Crime and Cyber Security
The Hacker News
The Hacker News
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
IntelliJ IDEA : IntelliJ IDEA – the Leading IDE for Professional Development in Java and Kotlin | The JetBrains Blog
爱范儿
爱范儿
A
Arctic Wolf
L
LINUX DO - 最新话题
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More

博客园 - 小纸条

ruoyiai 启动指南 反向传播 numpy的使用 B 和 B+树 红黑树 ruoyi-vue 梯度下降法 博弈论 离散化 AcWing 906. 区间分组 AcWing 908 最大不相交区间数量 AcWing 905. 区间选点 AcWing 104. 货仓选址 动态规划经典题 窗口函数 1226. 哲学家进餐 1195. 交替打印字符串 1117. H2O 生成 1116. 打印零与奇偶数 关联子查询
AcWing 907. 区间覆盖
小纸条 · 2025-11-22 · via 博客园 - 小纸条

AcWing 907. 区间覆盖

一、题目核心

  • 给定目标线段区间 [s, t]N 个闭区间,选择最少数量的区间完全覆盖目标线段,无法覆盖则输出 -1
  • 数据范围:1 ≤ N ≤ 10^5,区间端点可取值范围 [-10^9, 10^9]

二、核心解法:贪心算法

核心思路

按左端点排序后,每次在能覆盖当前起点的区间中,选择右端点最大的区间,最大化覆盖范围,从而最小化区间使用数量。

具体步骤

AcWing 907 “区间覆盖”问题(即:用最少的给定区间完全覆盖目标区间 [s, t])在 Java 中的经典实现如下。该解法采用贪心策略 + 双指针,时间复杂度为 O(n log n)(主要来自排序)。

✅ 题目回顾

  • 输入
    • 目标区间 [s, t]
    • N 个候选闭区间 [a_i, b_i]
  • 输出
    • 能完全覆盖 [s, t] 所需的最少区间数
    • 若无法覆盖,输出 -1

✅ Java 实现(标准写法)

import 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);
    }
}

🔍 算法逻辑说明

  1. 排序:按区间左端点 l 升序排列,确保我们从左到右处理。
  2. 贪心扩展
    • 维护当前已覆盖到的位置 currentEnd(初始为 s)。
    • 在所有满足 l <= currentEnd 的区间中,选择 r 最大的那个(即延伸最远)。
  3. 失败判断
    • 如果一轮扫描后 maxRight 没有超过 currentEnd,说明出现“空隙”,无法继续覆盖。
  4. 终止条件:当 currentEnd >= t 时,成功覆盖目标区间。

🧪 示例测试

输入

1 5
3
-1 3
2 4
3 5

执行过程

  • 排序后区间:[-1,3], [2,4], [3,5]
  • 第1轮:currentEnd=1,可选 [-1,3]maxRight=3res=1
  • 第2轮:currentEnd=3,可选 [2,4], [3,5]maxRight=5res=2
  • 5 >= 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;
    }
}