当前位置: 首页 > news >正文

贪心算法解决固定长度区间覆盖问题:最少区间数计算

题目描述

给定实直线上的 n 个点和一个固定长度 k 的闭区间,要求选择若干个这样的闭区间(区间起点、终点可任意选择),使得所有点都被区间覆盖,且使用的区间数量最少。最终输出最少需要的区间数。

输入格式

  • 第一行:两个正整数 n(点的数量,n≤10000)和 k(区间固定长度,k≤100);
  • 第二行:n 个整数,代表 n 个点在实直线上的坐标(可能存在重复点)。

输出格式

  • 一个整数,代表覆盖所有点所需的最少固定长度闭区间数。

解题思路:贪心算法的核心逻辑

要解决 “最少区间覆盖” 问题,贪心算法是最优选择,其核心思想是每次尽可能用一个区间覆盖更多的点,具体步骤如下:

  1. 排序点坐标:首先将所有点按坐标从小到大排序。排序是贪心的基础 —— 只有有序的点,才能保证 “从左到右覆盖” 的逻辑正确性。
  2. 初始化区间:以排序后的第一个点为起点,构建第一个闭区间 [current, current + k]current 初始为第一个点的坐标),此时最少区间数 cnt 初始化为 1(至少需要一个区间)。
  3. 遍历覆盖点:从第二个点开始依次检查每个点:
    • 若当前点在当前区间 [current, current + k] 内(即 nums[i] ≤ current + k),则该点已被覆盖,无需新增区间;
    • 若当前点超出当前区间(即 nums[i] > current + k),则需要新增一个区间,新区间的起点设为当前点(保证新区间能覆盖该点,且尽可能覆盖后续更多点),同时 cnt 加 1。
  4. 输出结果:遍历完成后,cnt 即为最少需要的区间数。

完整代码实现

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;/*** 计算覆盖所有点所需的最少固定长度闭区间数* @param k:固定区间长度* @param n:点的数量* @param nums:存储点坐标的向量(传入引用避免拷贝开销)*/
void calculateMinIntervals(int k, int n, vector<int>& nums) {// 步骤1:将点按坐标从小到大排序(贪心算法的前提)sort(nums.begin(), nums.end());int min_intervals = 1;  // 最少区间数,至少需要1个int current_start = nums[0];  // 第一个区间的起点(从第一个点开始)// 步骤2:遍历所有点,判断是否需要新增区间for (int i = 1; i < n; ++i) {// 若当前点超出当前区间的范围(current_start + k 是当前区间的终点)if (current_start + k < nums[i]) {min_intervals++;  // 新增一个区间current_start = nums[i];  // 新区间的起点设为当前点}// 若当前点在区间内,无需操作}// 输出结果cout << min_intervals << endl;
}int main() {int n, k;// 输入点的数量和区间长度cin >> n >> k;vector<int> points(n);// 输入n个点的坐标for (int i = 0; i < n; ++i) {cin >> points[i];}// 调用函数计算最少区间数calculateMinIntervals(k, n, points);return 0;
}

代码解析

1. 关键变量说明

  • min_intervals:记录最少区间数,初始为 1(因为即使只有一个点,也需要一个区间覆盖);
  • current_start:当前区间的起点,初始为排序后第一个点的坐标,后续每次新增区间时更新为当前点的坐标;
  • sort(nums.begin(), nums.end()):排序是核心预处理步骤,确保点按从左到右的顺序处理,避免遗漏或重复覆盖。

2. 核心判断逻辑

if (current_start + k < nums[i]) {min_intervals++;current_start = nums[i];
}
  • 区间的终点是 current_start + k(因为区间长度为 k,闭区间 [current_start, current_start + k] 刚好覆盖长度 k);
  • 当 nums[i] 大于区间终点时,说明当前点不在当前区间内,必须新增一个区间,且新区间的起点设为 nums[i](这样能最大限度覆盖后续的点,减少区间总数)。

3. 处理重复点

若输入中存在重复点(如 [2, 2, 3]),排序后重复点会相邻,此时重复点必然在同一个区间内,无需额外处理,代码会自动覆盖。

测试案例与运行结果

案例 1:基础覆盖

5 3
1 2 3 4 5

排序后点[1, 2, 3, 4, 5]
过程

  1. 第一个区间 [1, 4],覆盖 1、2、3、4;
  2. 点 5 超出 [1,4],新增区间 [5, 8],覆盖 5;
    输出2

案例 2:含负坐标

输入

6 2
-1 0 1 3 4 5

排序后点[-1, 0, 1, 3, 4, 5]
过程

  1. 第一个区间 [-1, 1],覆盖 -1、0、1;
  2. 点 3 超出 [-1,1],新增区间 [3, 5],覆盖 3、4、5;
    输出2

案例 3:单个点

输入

1 10
5

过程:仅需一个区间 [5, 15] 覆盖点 5;
输出1

案例 4:重复点

输入

4 2
2 2 3 5

排序后点[2, 2, 3, 5]
过程

  1. 第一个区间 [2, 4],覆盖 2、2、3;
  2. 点 5 超出 [2,4],新增区间 [5,7]
    输出2

算法正确性证明

要证明贪心算法的正确性,需验证其满足贪心选择性质最优子结构性质

1. 贪心选择性质

“每次选择以当前未覆盖点为起点的区间,能覆盖最多后续点” 是最优选择。
假设存在更优的方案:在某个步骤中,没有选择当前未覆盖点 nums[i] 作为新区间起点,而是选择了 nums[i] 左侧的某个点 xx < nums[i])作为起点。此时区间 [x, x + k] 虽然能覆盖 nums[i],但后续点可能仍需新增相同数量的区间(甚至更多),因此该选择不会比 “以 nums[i] 为起点” 更优。

2. 最优子结构性质

若覆盖前 i 个点的最少区间数为 m,则覆盖前 i+1 个点的最少区间数要么是 m(第 i+1 个点在第 m 个区间内),要么是 m+1(第 i+1 个点超出第 m 个区间,需新增区间)。这种 “局部最优解扩展为全局最优解” 的特性,证明了问题具有最优子结构。

综上,该贪心算法能得到全局最优解(最少区间数)。

算法复杂度分析

  • 时间复杂度O(n log n)
    主要耗时操作是对 n 个点的排序(O(n log n)),后续遍历点的操作是 O(n),整体复杂度由排序决定。
  • 空间复杂度O(1)(不含输入存储)
    仅使用了 min_intervalscurrent_start 等常数个变量,空间开销与 n 无关。

总结

本文通过贪心算法解决了固定长度区间覆盖问题,核心是 “排序后从左到右覆盖,每次尽可能覆盖更多点”。代码简洁高效,能处理 n≤10000 的输入规模,且正确性有严格的数学证明支撑。该思路不仅适用于本题,还可推广到 “区间覆盖” 类问题的变种(如区间选点、最长不重叠区间等),是算法学习中的基础经典模型。

http://www.dtcms.com/a/361420.html

相关文章:

  • CICD实战(2) - 使用Arbess+GitLab+SonarQube实现Java项目快速扫描/构建/部署
  • 【MySQL详解】索引、事务、锁、日志
  • 【C++上岸】C++常见面试题目--数据结构篇(第十六期)
  • 科学研究系统性思维的方法体系:数据收集
  • 11,FreeRTOS队列理论知识
  • linux内核 - ext 文件系统介绍
  • 嵌入式学习日志————I2C通信外设
  • 拥抱智能高效翻译 ——8 款视频翻译工具深度测评
  • Linux Shell 脚本中括号类型及用途
  • 【项目思维】嵌入式产业链与技术生态
  • 2025 最新React前端面试题目 (9月最新)
  • Windows Qt5.15.17源码使用VS2019编译安装
  • 六、练习3:Gitee平台操作
  • 瑞芯微RK3576平台FFmpeg硬件编解码移植及性能测试实战攻略
  • 深入掌握 Flask 配置管理:从基础到高级实战
  • 校园网IP地址要如何管理
  • MySQL基础知识保姆级教程(四)基础语句
  • 人工智能学习:NLP文本处理的基本方法
  • C++函数执行时间统计工具:轻量级性能分析的最佳实践
  • 触想轨道交通应用案例集锦(一)
  • PAT 1089 Insert or Merge
  • G156HAN04.0 宽温域高亮工业屏技术白皮书
  • 矩阵中寻找好子矩阵
  • leetcode5( 多数元素)
  • 力扣 23 912题(堆)
  • MySQL 体系结构
  • 09.《路由基础知识解析和实践》
  • 【C#实战】使用ListBox控件与生成器模式构建灵活多变的金融资产管理系统
  • 金融数据安全
  • 云原生新手入门完整学习指南