题目描述
在某个项目中有多个任务(用tasks数组表示)需要您进行处理,其中tasks[i]=[si,ei],你可以在si <= day <= ei中的任意一天处理该任务,
请返回你可以处理的最大任务数。
输入描述
第一行为任务数量n,1 <=n<= 100000。后面n行表示各个任务的开始时间和终止时间,使用si,ei表示,1 <= si <= ei <= 100000
输出描述
输出为一个整数,表示可以处理的最大任务数。
** 用例
输入
3
1 1
1 2
1 3
输出
3
思路
一、问题核心背景
本题为经典的「区间调度最大化问题」,要求在 si ≤ day ≤ ei 范围内为每个任务分配唯一天数,最大化处理的任务数。基础贪心(直接选任务结束时间作为处理时间)因浪费早期空闲天存在逻辑漏洞,并查集 和 小顶堆(优先队列) 是两种严格贴合题目条件的最优解法。
二、并查集解法
1. 核心原理
核心思想是为每个任务快速找到 [si, ei] 范围内的「最早空闲天」,避免浪费早期天数,最大化后续任务的分配空间。
- 并查集的作用:用数组
parent记录每个天数的「最终空闲父节点」,通过「查找(find)+ 路径压缩」实现 O(1) 级别的空闲天查询,通过「更新父节点」标记天数已被占用。 - 核心步骤:
- 排序:将所有任务按「结束时间 ei」升序排列(优先处理结束早的任务,减少过期风险);
- 并查集初始化:构建
parent数组,parent[day] = day(初始时每个天数的空闲父节点是自身); - 查找空闲天:对每个任务 [si, ei],调用
find(si)找到 si 对应的最早空闲天x; - 分配与更新:若
x ≤ ei(存在可用天),则分配该天(计数+1),并将parent[x] = x + 1(标记 x 已占用,下次查询直接指向 x+1)。
2. 关键细节
- 路径压缩:
find函数中,若parent[x] ≠ x,递归查找并将parent[x]指向最终空闲父节点,避免重复遍历,将查询复杂度降到近乎 O(1); - 排序必要性:按结束时间升序,确保先处理“时间窗口更紧张”的任务,避免因先处理晚结束的任务导致短窗口任务过期。
3. 时间复杂度
- 排序:O(n log n)(主导复杂度,n 为任务数);
- 并查集操作:每个任务的
find操作因路径压缩,均摊复杂度为 O(α(n))(α 是阿克曼函数的反函数,n=1e5 时 α(n)≈3,接近常数); - 总体复杂度:O(n log n),完全适配 n=1e5 的大数据量。
4. 空间复杂度
- O(maxDay):
parent数组的长度取决于所有任务的最大结束时间 maxDay(最坏情况为 1e5,符合题目约束)。
三、小顶堆(优先队列)解法
1. 核心原理
模拟「按天处理任务」的过程,每天优先处理「结束时间最早」的可用任务,确保不浪费当天时间,同时避免任务过期。
- 小顶堆的作用:维护当前所有可用任务的结束时间,堆顶为「最早结束的任务」,保证每天处理的是最紧急的任务。
- 核心步骤:
- 排序:将所有任务按「开始时间 si」升序排列;
- 按天遍历:从第 1 天遍历到所有任务的最大结束时间 maxDay;
- 任务入堆:将当天开始的所有任务(si = 当前天)的结束时间 ei 加入小顶堆;
- 清理过期任务:弹出堆中所有结束时间 < 当前天的任务(已无可用时间,无需处理);
- 处理任务:若堆非空,弹出堆顶任务(最早结束),计数+1(代表当天处理该任务)。
2. 关键细节
- 小顶堆的特性:堆的插入/弹出操作复杂度为 O(log k)(k 为堆中任务数,k ≤ n);
- 按天遍历的边界:只需遍历到 maxDay(所有任务的最大结束时间),无需遍历到 1e5(可提前预判);
- 过期任务清理:必须先清理过期任务,否则会处理已无时间窗口的任务,导致结果错误。
3. 时间复杂度
- 排序:O(n log n);
- 堆操作:每个任务最多入堆/出堆各一次,总复杂度 O(n log n);
- 按天遍历:O(maxDay),但 maxDay ≤ 1e5(题目约束),且实际中可提前终止(无任务时直接退出);
- 总体复杂度:O(n log n + maxDay),n=1e5、maxDay=1e5 时仍可高效运行。
4. 空间复杂度
- O(n):小顶堆最多存储所有任务(最坏情况),排序后的任务数组也需 O(n) 空间。
四、两种解法对比
| 维度 | 并查集解法 | 小顶堆解法 |
|---|---|---|
| 核心思路 | 为任务找最早空闲天 | 按天处理最紧急任务 |
| 时间复杂度 | O(n log n)(更优) | O(n log n + maxDay) |
| 空间复杂度 | O(maxDay) | O(n) |
| 适用场景 | 大数据量、时间范围明确 | 需直观模拟每日任务分配 |
| 代码实现 | 简洁(无复杂数据结构) | 稍复杂(需实现堆) |
| 核心优势 | 效率极高,路径压缩降复杂度 | 逻辑直观,贴近业务场景 |
代码
// 并查集
function solution() {
const n = Number(readline());
const tasks = [];
for (let i = 0; i < n; i++) {
tasks.push(readline().split(' ').map(Number));
}
// 按结束时间升序
tasks.sort((a, b) => a[1] - b[1]);
const maxDay = tasks[tasks.length-1][1];
const parent = Array(maxDay + 1);
for (let i = 1; i <= maxDay; i++<

最低0.47元/天 解锁文章
549

被折叠的 条评论
为什么被折叠?



