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

推荐订阅源

月光博客
月光博客
T
Troy Hunt's Blog
P
Proofpoint News Feed
H
Help Net Security
博客园 - 叶小钗
N
Netflix TechBlog - Medium
F
Full Disclosure
Vercel News
Vercel News
C
Cyber Attacks, Cyber Crime and Cyber Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
GbyAI
GbyAI
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 【当耐特】
Martin Fowler
Martin Fowler
V
V2EX
Latest news
Latest news
L
LangChain Blog
The Register - Security
The Register - Security
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
S
Schneier on Security
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
N
News and Events Feed by Topic
M
MIT News - Artificial intelligence
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
The Exploit Database - CXSecurity.com
Microsoft Security Blog
Microsoft Security Blog
S
Secure Thoughts
A
About on SuperTechFans
人人都是产品经理
人人都是产品经理
T
The Blog of Author Tim Ferriss
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Spread Privacy
Spread Privacy
S
Securelist
Forbes - Security
Forbes - Security
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Last Week in AI
Last Week in AI
T
Threat Research - Cisco Blogs
V
Vulnerabilities – Threatpost
MyScale Blog
MyScale Blog
G
Google Developers Blog
L
Lohrmann on Cybersecurity
博客园 - Franky
T
Tor Project blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
V
Visual Studio Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
Y
Y Combinator Blog

博客园 - 小纸条

模型微调 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;
    }
}