【2025刷题笔记】- 区间交叠问题

刷题笔记合集🔗

区间交叠问题

问题描述

给定坐标轴上的一组线段,线段的起点和终点均为整数并且长度不小于1,请你从中找到最少数量的线段,这些线段可以覆盖所有线段。

输入格式

第一行输入为所有线段的数量,不超过10000,后面每行表示一条线段,格式为"", 分别表示起点和终点,取值范围是

输出格式

最少线段数量,为正整数。

样例输入

3
1,4
2,5
3,6

样例输出

2

数据范围

样例 解释说明
样例1 选择[1,4]和[3,6]这两条线段即可覆盖所有线段
  • 线段数量
  • 线段端点取值范围
  • 线段长度不小于1

题解

这道题目要求我们从给定的线段集合中选出最少数量的线段,使得它们能覆盖所有给定的线段。

首先,需要理解什么是"覆盖":如果线段A完全包含在一条或多条选择的线段内,则称线段A被覆盖。

解决这个问题的关键是贪心策略。我们可以按照以下步骤处理:

  1. 将所有线段按照起始位置升序排序
  2. 维护一个栈(或列表)来保存需要的线段
  3. 遍历排序后的每一条线段,与栈顶线段比较:
    • A. 如果当前线段与栈顶线段没有交集,则将当前线段入栈
    • B. 如果当前线段完全包含在栈顶线段内,则跳过当前线段
    • C. 如果当前线段与栈顶线段有部分交集,则保留未覆盖部分
    • D. 如果当前线段完全包含栈顶线段,则弹出栈顶元素,重新与新的栈顶元素比较

例如,对于样例输入:

3
1,4
2,5
3,6

执行过程如下:

  1. 排序后的线段列表:[1,4], [2,5], [3,6]
  2. 将第一条线段[1,4]入栈
  3. 处理第二条线段[2,5]:
    • 它与栈顶线段[1,4]有交集
    • [2,5]的未覆盖部分是[4,5],将其入栈
  4. 处理第三条线段[3,6]:
    • 它完全包含栈顶线段[4,5],弹出[4,5]
    • 比较[3,6]与新栈顶[1,4],它们有交集
    • [3,6]的未覆盖部分是[4,6],将其入栈
  5. 最终栈中有[1,4]和[4,6],需要2条线段

这个贪心策略的核心思想是尽可能利用现有线段的覆盖范围,只保留确实需要的部分。

算法的时间复杂度是O(n log n),主要来自于对线段的排序。空间复杂度是O(n),用于存储需要的线段。

对于给定的约束(线段数量不超过10000),这个算法可以高效地解决问题。

参考代码

  • Python
import sys
input = lambda:sys.stdin.readline().strip()

# 读取线段数量
n = int(input())

# 读取所有线段
segments = []
for _ in range(n):
    x, y = map(int, input().split(','))
    segments.append([x, y])

# 按起始位置排序
segments.sort(key=lambda x: x[0])

# 求解函数
def min_covering_segments(segs):
    """
    计算覆盖所有线段所需的最少线段数
    
    参数:
        segs: 排序后的线段列表,每个线段为[start, end]形式
        
    返回:
        最少线段数量
    """
    if not segs:
        return 0
        
    # 初始化栈,放入第一个线段
    stack = [segs[0]]
    
    # 遍历剩余线段
    for i in range(1, len(segs)):
        seg = segs[i]
        
        # 处理每个线段时可能需要多次与栈顶比较
        while True:
            # 空栈时直接入栈
            if not stack:
                stack.append(seg)
                break
            
            s0, e0 = stack[-1]  # 栈顶线段
            s1, e1 = seg        # 当前线段
            
            # 当前线段起点在栈顶线段起点之前或相同
            if s1 <= s0:
                # 当前线段终点在栈顶线段起点之前,无法覆盖,跳过
                if e1 <= s0:
                    break
                # 当前线段终点在栈顶线段终点之前,被栈顶线段覆盖,跳过
                elif e1 < e0:
                    break
                # 当前线段完全包含栈顶线段,弹出栈顶,继续比较
                else:
                    stack.pop()
            # 当前线段起点在栈顶线段内部
            elif s1 < e0:
                # 当前线段被栈顶线段完全覆盖,跳过
                if e1 <= e0:
                    break
                # 当前线段部分被覆盖,添加未覆盖部分
                else:
                    stack.append([e0, e1])
                    break
            # 当前线段与栈顶线段无交集,直接入栈
            else:
                stack.append(seg)
                break
    
    # 返回需要的线段数量
    return len(stack)

# 输出结果
print(min_covering_segments(segments))
  • Cpp
#include <bits/stdc++.h>
using namespace std;

int main() {
    // 读取线段数量
    int n;
    cin >> n;
    
    // 读取所有线段
    vector<vector<int>> segs(n, vector<int>(2));
    for (int i = 0; i < n; i++) {
        string line;
        cin >> line;
        int pos = line.find(',');
        segs[i][0] = stoi(line.substr(0, 

剩余60%内容,订阅专栏后可继续查看/也可单篇购买

算法刷题笔记 文章被收录于专栏

本专栏收集并整理了一些刷题笔记

全部评论

相关推荐

行云流水1971:这份实习简历的优化建议: 结构清晰化:拆分 “校园经历”“实习经历” 板块(当前内容混杂),按 “实习→校园→技能” 逻辑排版,求职意向明确为具体岗位(如 “市场 / 运营实习生”)。 经历具象化:现有描述偏流程,需补充 “动作 + 数据”,比如校园活动 “负责宣传” 可加 “运营公众号发布 5 篇推文,阅读量超 2000+,带动 300 + 人参与”;实习内容补充 “协助完成 XX 任务,效率提升 X%”。 岗位匹配度:锚定目标岗位能力,比如申请运营岗,突出 “内容编辑、活动执行” 相关动作;申请市场岗,强化 “资源对接、数据统计” 细节。 信息精简:删减冗余表述(如重复的 “负责”),用短句分点,比如 “策划校园招聘会:联系 10 + 企业,组织 200 + 学生参与,到场率达 85%”。 技能落地:将 “Office、PS” 绑定经历,比如 “用 Excel 整理活动数据,输出 3 份分析表;用 PS 设计 2 张活动海报”,避免技能单独罗列。 优化后需强化 “经历 - 能力 - 岗位需求” 的关联,让实习 / 校园经历的价值更直观。 若需要进一步优化服务,私信
实习,投递多份简历没人回...
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务