pythonjavacjsc_0">【华为OD-E卷 - 招聘 100分(python、java、c++、js、c)】
题目
某公司组织一场公开招聘活动,假设由于人数和场地的限制,每人每次面试的时长不等,并已经安排给定,用(S1,E1)、 (S2,E2)、 (Sj,Ej)…(Si < Ei,均为非负整数)表示每场面试的开始和结束时间。
面试采用一对一的方式,即一名面试官同时只能面试一名应试者,一名面试官完成一次面试后可以立即进行下一场面试,且每个面试官的面试人次不超过 m。
为了支撑招聘活动高效顺利进行,请你计算至少需要多少名面试官
输入描述
- 输入的第一行为面试官的最多面试人次 m,第二行为当天总的面试场次 n,
接下来的 n 行为每场面试的起始时间和结束时间,起始时间和结束时间用空格分隔。
其中, 1 <= n, m <= 500
输出描述
- 输出一个整数,表示至少需要的面试官数量
用例
用例一:
输入:
2
5
1 2
2 3
3 4
4 5
5 6
输出:
3
用例二:
输入:
3
3
1 2
2 3
3 4
输出:
1
用例三:
输入:
3
3
8 35
5 10
1 3
输出:
2
python_82">python解法
- 解题思路:
- 题目理解:
给定两个整数 m 和 n,m 表示每个池子(或资源)最多可以容纳的任务数量,n 表示任务的总数。
接着输入 n 行数据,每行包含两个整数 s 和 e,表示一个任务的开始时间 s 和结束时间 e。
目标是将所有任务分配到若干个池子中,满足以下条件:
每个池子最多容纳 m 个任务。
同一个池子中的任务不能时间重叠,即后一个任务的开始时间必须大于等于前一个任务的结束时间。
核心思路:
按结束时间排序:为了尽量多地安排任务,优先安排最早结束的任务。
分配任务到池子:遍历排序后的任务列表,将每个任务依次分配到满足条件的池子中:
如果当前池子未满且最后一个任务的结束时间小于等于当前任务的开始时间,则将该任务放入此池子。
如果没有找到合适的池子,则继续检查下一个池子。
统计池子数量:最终统计非空池子的数量,即为所需的池子数
python"># 读取池子的最大任务数m和任务总数n
m = int(input())
n = int(input())# 读取n个任务的开始时间和结束时间,存入data列表
data = [list(map(int, input().split())) for _ in range(n)]def calc():# 按任务的结束时间升序排序,以便尽可能早地安排任务data.sort(key=lambda x: x[1])# 初始化池子列表,每个池子是一个列表,用于存放任务的结束时间pools = [[] for _ in range(n)]i = 0# 遍历每个任务while i < len(data):s, e = data[i] # 当前任务的开始时间s和结束时间ej = 0# 尝试将任务分配到某个池子中while j < len(pools):# 检查当前池子是否有空间,并且任务时间是否不冲突if len(pools[j]) < m and (len(pools[j]) == 0 or pools[j][-1] <= s):pools[j].append(e) # 将任务的结束时间加入池子break # 成功放入池子后,跳出循环j += 1 # 检查下一个池子i += 1 # 处理下一个任务# 统计非空池子的数量,表示总共用了多少个池子return len([p for p in pools if len(p) > 0])# 输出所需的池子数量
print(calc())
java_137">java解法
- 解题思路
- 题目理解:
输入包括两个整数 m 和 n:
m 表示每个池子(或资源)最多可以容纳的任务数量。
n 表示任务的总数。
接下来输入 n 行,每行包含两个整数,分别表示任务的开始时间 s 和结束时间 e。
目标是将所有任务分配到若干个池子中,满足以下条件:
每个池子最多容纳 m 个任务。
同一个池子中的任务不能时间重叠,即后一个任务的开始时间必须大于等于前一个任务的结束时间。
最终输出所需的最少池子数量。
算法思路:
排序任务:首先按任务的结束时间升序排序,以便尽可能早地安排任务,从而减少池子的使用。
分配任务到池子:
遍历每个任务,尝试将其放入已存在的池子中。
如果当前池子未满,且池子中最后一个任务的结束时间小于等于当前任务的开始时间,则将任务放入该池子。
如果没有找到合适的池子,说明需要新开一个池子。
统计池子数量:最后统计非空池子的数量,得到所需的池子数
java">import java.util.*;public class Main {// 计算所需池子数量的方法public static int calc(int m, int n, int[][] data) {// 按任务的结束时间升序排序,以便尽可能早地安排任务Arrays.sort(data, Comparator.comparingInt(a -> a[1]));// 初始化池子列表,每个池子是一个存储任务结束时间的列表List<List<Integer>> pools = new ArrayList<>();for (int i = 0; i < n; i++) {pools.add(new ArrayList<>()); // 最多创建n个池子}// 遍历每个任务for (int i = 0; i < data.length; i++) {int s = data[i][0]; // 任务的开始时间int e = data[i][1]; // 任务的结束时间boolean added = false; // 标记任务是否成功分配到池子// 尝试将任务放入现有池子for (List<Integer> pool : pools) {// 检查池子是否未满,且当前任务时间不与池子中的任务冲突if (pool.size() < m && (pool.isEmpty() || pool.get(pool.size() - 1) <= s)) {pool.add(e); // 将任务的结束时间添加到池子中added = true; // 标记任务已成功分配break; // 找到合适的池子后,跳出循环}}// 如果没有找到合适的池子,说明任务无法分配(按题意不会出现这种情况)if (!added) {break;}}// 统计非空池子的数量,即为所需池子数量int count = 0;for (List<Integer> pool : pools) {if (!pool.isEmpty()) {count++;}}return count;}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);// 读取池子的最大任务数m和任务总数nint m = scanner.nextInt();int n = scanner.nextInt();int[][] data = new int[n][2]; // 用于存储每个任务的开始和结束时间// 读取每个任务的时间for (int i = 0; i < n; i++) {data[i][0] = scanner.nextInt(); // 任务的开始时间data[i][1] = scanner.nextInt(); // 任务的结束时间}// 调用计算方法并输出所需池子数量System.out.println(calc(m, n, data));scanner.close(); // 关闭输入流}
}
C++解法
- 解题思路
更新中
C解法
输入两个整数 m 和 n:
m:每个池子最多可以容纳的任务数量。
n:总共有 n 个任务。
接下来输入 n 行,每行包含两个整数,表示任务的开始时间 start 和结束时间 end。
任务需要分配到若干个池子中,满足以下条件:
每个池子最多容纳 m 个任务。
同一个池子中的任务不能有时间重叠,即后一个任务的开始时间必须大于等于前一个任务的结束时间。
目标是计算并输出所需的最少池子数量。
算法思路:
按结束时间排序:为了尽量减少池子的使用,先将任务按结束时间升序排序,优先安排结束时间早的任务。
分配任务到池子:
遍历每个任务,尝试将其放入已存在的池子中。
如果池子未满,且池子中最后一个任务的结束时间小于等于当前任务的开始时间,则将任务放入该池子。
如果没有找到合适的池子,则新开一个池子。
统计池子数量:最后统计非空池子的数量,即为所需池子的数量
#include <stdio.h>
#include <stdlib.h>// 定义任务区间结构体,包含开始时间和结束时间
typedef struct {int start;int end;
} Interval;// 比较函数:按任务的结束时间升序排序
int compareIntervals(const void* a, const void* b) {Interval* interval1 = (Interval*)a;Interval* interval2 = (Interval*)b;return interval1->end - interval2->end;
}// 计算所需池子数量的函数
int calculatePools(int m, int n, Interval* intervals) {// 将任务按结束时间排序,方便优先安排早结束的任务qsort(intervals, n, sizeof(Interval), compareIntervals);// 初始化池子,每个池子存储任务的结束时间int pools[MAX_POOLS][MAX_N] = { 0 }; // pools[i][j] 表示第 i 个池子的第 j 个任务的结束时间int poolSizes[MAX_POOLS] = { 0 }; // 记录每个池子当前的任务数量int poolCount = 0; // 当前池子的数量// 遍历每个任务,尝试分配到合适的池子for (int i = 0; i < n; i++) {int start = intervals[i].start; // 当前任务的开始时间int end = intervals[i].end; // 当前任务的结束时间int added = 0; // 标记当前任务是否已成功分配到池子// 尝试将任务放入已存在的池子中for (int j = 0; j < poolCount; j++) {// 检查池子是否未满,且任务时间不冲突if (poolSizes[j] < m && (poolSizes[j] == 0 || pools[j][poolSizes[j] - 1] <= start)) {pools[j][poolSizes[j]++] = end; // 将任务的结束时间放入池子added = 1; // 标记任务已分配break; // 找到合适的池子后退出循环}}// 如果没有合适的池子,创建新池子if (!added) {pools[poolCount][poolSizes[poolCount]++] = end; // 新池子存放当前任务poolCount++; // 池子数量加一}}// 返回池子的总数量return poolCount;
}int main() {int m, n;scanf("%d %d", &m, &n); // 读取池子的最大容量m和任务数量nInterval intervals[MAX_N]; // 存储任务的开始和结束时间for (int i = 0; i < n; i++) {scanf("%d %d", &intervals[i].start, &intervals[i].end); // 读取每个任务}// 计算并输出所需池子数量int result = calculatePools(m, n, intervals);printf("%d\n", result);return 0;
}
JS解法
输入包括两个整数 m 和 n:
m 表示每个池子(或资源)最多可以容纳的任务数量。
n 表示任务的总数。
接下来输入 n 行,每行包含两个整数,表示任务的开始时间 start 和结束时间 end。
任务需要分配到若干个池子中,满足以下条件:
同一个池子中的任务不能有时间重叠,即后一个任务的开始时间必须大于等于前一个任务的结束时间。
每个池子最多容纳 m 个任务(不过代码中并未处理这个条件)。
最终目标是计算所需的最少池子数量。
算法思路:
按任务开始时间排序:首先将任务按开始时间升序排序,若开始时间相同,再按结束时间升序排序。
使用最小堆(优先队列)模拟池子分配:
heap 数组存储当前每个池子的最新结束时间。
遍历任务列表,尝试将当前任务分配到已有的池子中:
如果最早结束的池子(即 heap 中的最小值)结束时间小于等于当前任务的开始时间,则表示该池子可以容纳当前任务,更新该池子的结束时间。
如果没有找到合适的池子,则新开一个池子,将当前任务的结束时间加入 heap。
每次操作后,重新排序 heap,确保最早结束的池子在最前面。
统计池子数量:遍历完所有任务后,heap 的长度即为所需的最少池子数量
javascript">const readline = require("readline");// 创建输入输出接口
const rl = readline.createInterface({input: process.stdin,output: process.stdout,
});const lines = []; // 存储输入数据
let m, n; // m: 每个池子的最大任务数, n: 任务数量// 读取输入数据
rl.on("line", (line) => {lines.push(line); // 每行输入存入数组// 读取前两行,分别为 m 和 nif (lines.length === 2) {m = parseInt(lines[0]); // 每个池子的最大任务数量n = parseInt(lines[1]); // 任务数量}// 当所有任务输入完毕后,调用计算函数if (n && lines.length === n + 2) {const ranges = lines.slice(2).map((line) => line.split(" ").map(Number)); // 解析任务的开始和结束时间console.log(getResult(ranges, m, n)); // 输出结果lines.length = 0; // 清空输入数组,准备读取下一组数据(如果有)}
});// 计算所需池子数量的函数
function getResult(ranges, m, n) {// 按任务的开始时间升序排序,若开始时间相同,则按结束时间升序排序ranges.sort((a, b) => a[0] - b[0] || a[1] - b[1]);const heap = []; // 最小堆,存储每个池子的最新结束时间// 遍历每个任务,尝试分配到池子for (let [start, end] of ranges) {let assigned = false; // 标记任务是否已分配到池子// 如果最早结束的池子结束时间 <= 当前任务的开始时间,表示可以复用该池子if (heap.length && heap[0] <= start) {heap.shift(); // 移除最早结束的池子(表示该池子已分配当前任务)heap.push(end); // 将当前任务的结束时间放入池子assigned = true;}// 如果没有合适的池子,创建新池子if (!assigned) {heap.push(end);}// 重新排序堆,确保最早结束的池子在最前面heap.sort((a, b) => a - b);}return heap.length; // 返回池子的数量
}
注意:
如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏