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

题目描述

给定实直线上的 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 即为最少需要的区间数。

完整代码实现

cpp 复制代码
#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 的输入规模,且正确性有严格的数学证明支撑。该思路不仅适用于本题,还可推广到 "区间覆盖" 类问题的变种(如区间选点、最长不重叠区间等),是算法学习中的基础经典模型。

相关推荐
健康有益科技5 小时前
慢病管理重构药店价值:数字化平台与物联网技术如何驱动行业升级?
大数据·人工智能·算法·软件工程·健康医疗·零售
野犬寒鸦6 小时前
力扣hot100:缺失的第一个正数(哈希思想)(41)
java·数据结构·后端·算法·leetcode·哈希算法
闪电麦坤957 小时前
数据结构:开放散列(Open Hashing)
数据结构·算法·哈希算法·散列表
白菜帮张同学9 小时前
LP嵌入式软件/驱动开发笔试/面试总结
数据结构·驱动开发·经验分享·笔记·学习·算法·面试
熊大与iOS10 小时前
iOS 长截图的完美实现方案 - 附Demo源码
android·算法·ios
Elylicery10 小时前
【职业】算法与数据结构专题
数据结构·算法
岁月静好202510 小时前
Leetcode二分查找(3)
算法·leetcode·职场和发展
一支鱼10 小时前
leetcode-4-寻找两个正序数组的中位数
算法·leetcode·typescript
Christo311 小时前
TSMC-1987《Convergence Theory for Fuzzy c-Means: Counterexamples and Repairs》
人工智能·算法·机器学习·kmeans