【OD机试题笔记】可以处理的最大任务数

题目描述

在某个项目中有多个任务(用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) 级别的空闲天查询,通过「更新父节点」标记天数已被占用。
  • 核心步骤
    1. 排序:将所有任务按「结束时间 ei」升序排列(优先处理结束早的任务,减少过期风险);
    2. 并查集初始化:构建 parent 数组,parent[day] = day(初始时每个天数的空闲父节点是自身);
    3. 查找空闲天:对每个任务 [si, ei],调用 find(si) 找到 si 对应的最早空闲天 x
    4. 分配与更新:若 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. 核心原理

模拟「按天处理任务」的过程,每天优先处理「结束时间最早」的可用任务,确保不浪费当天时间,同时避免任务过期。

  • 小顶堆的作用:维护当前所有可用任务的结束时间,堆顶为「最早结束的任务」,保证每天处理的是最紧急的任务。
  • 核心步骤
    1. 排序:将所有任务按「开始时间 si」升序排列;
    2. 按天遍历:从第 1 天遍历到所有任务的最大结束时间 maxDay;
    3. 任务入堆:将当天开始的所有任务(si = 当前天)的结束时间 ei 加入小顶堆;
    4. 清理过期任务:弹出堆中所有结束时间 < 当前天的任务(已无可用时间,无需处理);
    5. 处理任务:若堆非空,弹出堆顶任务(最早结束),计数+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++<
<think>好的,用户想了解华为OD试中的“任务处理”题目及解答。首先,我需要确认用户提到的具体题目内容。根据提供的引用内容,特别是引用[2]和引用[3],华为OD试涉及任务处理的题目通常考查贪心算法,例如2024年D卷的“可以处理最大任务数”。题目描述可能涉及任务的时间安排,要求在特定约束下找到能处理最大任务数。 接下来,我需要整理该题的具体要求和解题思路。题目可能给出每个任务的开始和结束时间,或者任务的时间段,要求选择不重叠的任务以最大化数量。这里需要应用贪心算法,通常按照结束时间排序,然后依次选择不冲突的任务。 然后,考虑如何用代码实现这一逻辑。根据引用[2]提到的Java解法,但用户可能需要其他语言版本,比如Python。需要确保代码结构清晰,步骤正确,比如排序任务、遍历并计数。 同时,用户可能希望了解解题的详细步骤,例如为什么选择按结束时间排序,以及贪心策略的正确性证明。这部分需要简明扼要地解释,确保用户理解算法的核心思想。 另外,用户提供的引用[3]提到华为试题目分值和难度,因此可能需要强调此类题目在考试中的位置和重要性,帮助用户合理分配准备时间。引用[4]提到的资料和源码也可能对用户有帮助,但当前问题主要集中在题目解答本身。 最后,生成相关问题时要围绕任务处理、贪心算法优化、类似题目以及华为OD试的其他常见题型,确保用户能进一步扩展学习。</think>### 华为OD试“任务处理”题目及解答示例 #### 题目描述(简化版) 给定一组任务,每个任务有开始时间$s_i$和结束时间$e_i$,要求在时间轴上选择尽可能多的任务,且这些任务时间不重叠。求最多可以处理任务数。 #### 解题思路 1. **贪心策略** 将任务按结束时间$e_i$升序排序,优先选择结束早的任务,为后续任务留出更多时间[^2]。 2. **实现步骤** - 排序任务列表 - 遍历任务,选择不重叠的任务 #### 代码实现(Python) ```python def max_tasks(tasks): # 按结束时间排序 tasks.sort(key=lambda x: x[1]) count = 0 last_end = -1 for s, e in tasks: if s >= last_end: count += 1 last_end = e return count # 示例输入 tasks = [(1, 3), (2, 5), (4, 7), (6, 9)] print(max_tasks(tasks)) # 输出: 2(选择任务1和3) ``` #### 复杂度分析 - **时间复杂度**:$O(n \log n)$,排序主导 - **空间复杂度**:$O(1)$ #### 关键点 - **排序依据**:选择结束时间最早的能最大化剩余时间窗口[^2] - **重叠判断**:当前任务开始时间必须≥上一个任务的结束时间 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值