You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

152 lines
4.1 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package class_2023_03_4_week;
import java.util.Arrays;
import java.util.TreeMap;
// 来自华为
// 给你 n 个任务和 m 个工人
// 每个任务需要一定的力量值才能完成
// 需要的力量值保存在下标从 0 开始的整数数组 tasks 中
// 第 i 个任务需要 tasks[i] 的力量才能完成
// 每个工人的力量值保存在下标从 0 开始的整数数组 workers 中
// 第 j 个工人的力量值为 workers[j]
// 每个工人只能完成 一个 任务
// 且力量值需要 大于等于 该任务的力量要求值, 即 workers[j] >= tasks[i]
// 除此以外,你还有 pills 个神奇药丸
// 可以给 一个工人的力量值 增加 strength
// 你可以决定给哪些工人使用药丸
// 但每个工人 最多 只能使用 一片 药丸
// 给你下标从 0 开始的整数数组tasks 和 workers 以及
// 两个整数 pills 和 strength ,请你返回 最多 有多少个任务可以被完成。
// 测试链接 : https://leetcode.cn/problems/maximum-number-of-tasks-you-can-assign/
public class Code02_MaximumNumberOfTasksYouCanAssign {
// 时间复杂度O(N * (logN)平方)
public static int maxTaskAssign1(int[] tasks, int[] workers, int pills, int strength) {
// l......r
// 0 n
int l = 0;
int r = tasks.length;
int m, ans = 0;
// n个任务如果只要求其中K个任务完成选最小工作量的K个任务
// O(n * log n)
Arrays.sort(tasks);
// n个任务如果只要求其中K个任务完成让能力最大的K个工人去执行
// O(m * log m)
Arrays.sort(workers);
// 0....n
// log n * n * log n
while (l <= r) {
// m是当前要完成的任务数量
m = (l + r) / 2;
// tasks[0...m-1]
// workers [ m个人]
// yeah1至少要吃多少药
if (yeah1(tasks, 0, m - 1, workers, workers.length - m, workers.length - 1, strength) <= pills) {
ans = m;
l = m + 1;
} else {
r = m - 1;
}
}
return ans;
}
public static int yeah1(int[] tasks, int tl, int tr, int[] workers, int wl, int wr, int strength) {
if (wl < 0) {
return Integer.MAX_VALUE;
}
TreeMap<Integer, Integer> taskMap = new TreeMap<>();
// tasks[tl....tr]
for (int i = tl; i <= tr; i++) {
taskMap.put(tasks[i], taskMap.getOrDefault(tasks[i], 0) + 1);
}
int ans = 0;
// works[wl..wr]
for (int i = wl; i <= wr; i++) {
Integer job = taskMap.floorKey(workers[i]);
if (job != null) {
int times = taskMap.get(job);
if (times == 1) {
taskMap.remove(job);
} else {
taskMap.put(job, times - 1);
}
} else {
// 吃药了!
job = taskMap.floorKey(workers[i] + strength);
if (job == null) {
return Integer.MAX_VALUE;
}
ans++;
int times = taskMap.get(job);
if (times == 1) {
taskMap.remove(job);
} else {
taskMap.put(job, times - 1);
}
}
}
return ans;
}
// 时间复杂度O(N * logN)
public static int maxTaskAssign2(int[] tasks, int[] workers, int pills, int strength) {
int[] help = new int[tasks.length];
int l = 0;
int r = tasks.length;
int m, ans = 0;
Arrays.sort(tasks);
Arrays.sort(workers);
while (l <= r) {
m = (l + r) / 2;
if (yeah2(tasks, 0, m - 1, workers, workers.length - m, workers.length - 1, strength, help) <= pills) {
ans = m;
l = m + 1;
} else {
r = m - 1;
}
}
return ans;
}
public static int yeah2(int[] tasks, int tl, int tr, int[] workers, int wl, int wr, int strength, int[] help) {
if (wl < 0) {
return Integer.MAX_VALUE;
}
int l = 0;
int r = 0;
int ti = tl;
int ans = 0;
// help : 辅助队列,双端队列!双端队列用数组实现!
for (int wi = wl; wi <= wr; wi++) {
// 4 6 7
// 0 1 2
// ti ti ti
// 工人 6
// help : 0 1
// 0 1 2 3 ...
// l r
for (; ti <= tr && tasks[ti] <= workers[wi]; ti++) {
help[r++] = ti;
}
if (l < r && tasks[help[l]] <= workers[wi]) {
l++;
} else {
// workers[wi] + strength
for (; ti <= tr && tasks[ti] <= workers[wi] + strength; ti++) {
help[r++] = ti;
}
if (l < r) {
ans++;
r--;
} else {
return Integer.MAX_VALUE;
}
}
}
return ans;
}
}