二分:你可以安排的最多任务数目
你可以安排的最多任务数目
leetcode.cn/problems/maximum-number-of-tasks-you-can-assign/desc…
给你
n
个任务和m
个工人。每个任务需要一定的力量值才能完成,需要的力量值保存在下标从 0 开始的整数数组tasks
中,第i
个任务需要tasks[i]
的力量才能完成。每个工人的力量值保存在下标从 0 开始的整数数组workers
中,第j
个工人的力量值为workers[j]
。每个工人只能完成 一个 任务,且力量值需要 大于等于 该任务的力量要求值(即workers[j] >= tasks[i]
)。除此以外,你还有
pills
个神奇药丸,可以给 一个工人的力量值 增加strength
。你可以决定给哪些工人使用药丸,但每个工人 最多 只能使用 一片 药丸。给你下标从 0 开始的整数数组
tasks
和workers
以及两个整数pills
和strength
,请你返回 最多 有多少个任务可以被完成。
使用二分法,先选定答案,再验证答案是否能满足条件,以此来压缩范围,直到选取到最后答案
import java.util.Arrays;
import java.util.TreeMap;
class Solution {
public int maxTaskAssign(int[] tasks, int[] workers, int pills, int strength) {
Arrays.sort(tasks);
Arrays.sort(workers);
int l = 0, r = Math.min(tasks.length, workers.length);
while (l < r) {
int mid = l + r + 1 >> 1;
if (check(mid, tasks, workers, pills, strength)) {
l = mid;
} else {
r = mid - 1;
}
}
return l;
}
public boolean check(int x, int[] tasks, int[] workers, int pills, int strength) {
boolean[] used = new boolean[workers.length];
TreeMap<Integer, Integer> workerMap = new TreeMap<>();
// 取值最大的x个工人
for (int i = workers.length - x; i < workers.length; i++) {
// <工人能力值:出现次数>
workerMap.put(workers[i], workerMap.getOrDefault(workers[i], 0) + 1);
}
// 判断x个任务是否都能被处理,从贪心的角度来看一定优先处理值最小的任务
for (int i = x - 1; i >= 0; i--) {
Integer work = workerMap.ceilingKey(tasks[i]);
if (work != null) {
// 最大的能满足,就直接使用最大的,不使用药丸
// 查询相同元素剩余多少个
int count = workerMap.get(work);
if (count == 1) {
// 只剩一个,删除
workerMap.remove(work);
} else {
// 还有剩,更新数据即可
workerMap.put(work, count - 1);
}
} else {
// 比最大的大,如果有药丸,则要找到能使 workers[k] + strength >= tasks[i] 成立的最小的 k
if (pills == 0) {
return false;
}
pills--;
work = workerMap.ceilingKey(tasks[i] - strength);
if (work == null) {
// 找不到
return false;
}
// 逻辑同上
int count = workerMap.get(work);
if (count == 1) {
workerMap.remove(work);
} else {
workerMap.put(work, count - 1);
}
}
}
return true;
}
}