题目:
你有 n
个工作和 m
个工人。给定三个数组: difficulty
, profit
和 worker
,其中:
difficulty[i]
表示第i
个工作的难度,profit[i]
表示第i
个工作的收益。worker[i]
是第i
个工人的能力,即该工人只能完成难度小于等于worker[i]
的工作。
每个工人 最多 只能安排 一个 工作,但是一个工作可以 完成多次 。
- 举个例子,如果 3 个工人都尝试完成一份报酬为
$1
的同样工作,那么总收益为$3
。如果一个工人不能完成任何工作,他的收益为$0
。
返回 在把工人分配到工作岗位后,我们所能获得的最大利润 。
示例 1:
输入: difficulty = [2,4,6,8,10], profit = [10,20,30,40,50], worker = [4,5,6,7] 输出: 100 解释: 工人被分配的工作难度是 [4,4,6,6] ,分别获得 [20,20,30,30] 的收益。
示例 2:
输入: difficulty = [85,47,57], profit = [24,66,99], worker = [40,25,25] 输出: 0
提示:
n == difficulty.length
n == profit.length
m == worker.length
1 <= n, m <= 104
1 <= difficulty[i], profit[i], worker[i] <= 105
题解:
这道题目是一个典型的贪心算法问题。它要求我们在分配工人任务的时候,获得最大的利润。实际上,就是要对每个工人,都找到他们能力范围内、收益最大的工作。以下是完成这道题的步骤:
-
首先,我们需要将工作按难度排序,同时保留与之对应的利润。因为如果工作A比工作B难度低,且A的收益不低于B,那么我们永远不会选择B,因为所有能做B的工人都能做A,并且收益不会比B差。
-
然后,我们需要对于每个工作,都找出不小于这个工作难度的最大收益。我们更新一个数组,这样数组中的每个位置
i
,都记录了难度不超过difficulty[i]
的工作中,最大的收益。这通过前一步排序后的工作列表来完成,从难度最小的工作开始,逐步向难度更高的工作更新最大收益。 -
对于每个工人,我们需要快速找出他们能力范围内,最大可能收益的工作。由于我们已经有了一个根据难度排序并记录最大收益的数组,我们可以使用二分搜索来找出对于每一个工人能力范围内的最大收益。
-
最后,我们需要对所有的工人做遍历,根据每个工人能力,找到他们能够获取的最大收益,并将所有工人的收益相加,就得到了最终的答案。
-
特殊情况要注意处理,例如工人能力比所有工作难度都低,那么这样的工人是赚不到钱的。
代码:
import java.util.Arrays;
class Solution {
public int maxProfitAssignment(int[] difficulty, int[] profit, int[] worker) {
int n = difficulty.length;
// 创建一个数组,每个元素为锁对应工作的难度和收益
int[][] jobs = new int[n][];
for (int i = 0; i < n; i++) {
jobs[i] = new int[]{difficulty[i], profit[i]};
}
// 根据工作的难度进行排序
Arrays.sort(jobs, (a, b) -> a[0] - b[0]);
Arrays.sort(worker);
int maxProfit = 0, i = 0, best = 0;
for (int ability : worker) {
// 对于每个工人,寻找他们能够完成的难度最大的工作
while (i < n && ability >= jobs[i][0]) {
best = Math.max(best, jobs[i][1]);
i++;
}
// 累加获得的最大利润
maxProfit += best;
}
return maxProfit;
}
}
知识点解析:
-
基本数据结构:
- 使用数组(
int[]
)存储工作难度、收益和工人能力。 - 使用二维数组(
int[][]
)来创建工作对象,包含每个工作的难度和收益。
- 使用数组(
-
排序:
- 通过
Arrays.sort()
对工作数组进行排序,便于后续查找最佳工作。 - 使用lambda表达式作为
Comparator
来自定义排序逻辑,确保工作按难度排序。
- 通过
-
贪心算法:
- 遍历工人能力,为每个工人贪心地寻找能够完成的、收益最大的工作。
-
循环控制:
- 使用增强型
for
循环(for-each loop
)来遍历工人数组。 - 使用
while
循环来查找每个工人能够完成的最佳工作。
- 使用增强型
-
变量管理:
- 使用变量
i
来跟踪工作数组的当前索引。 - 使用变量
best
保持当前可获得的最大收益。
- 使用变量
-
逻辑运算:
- 使用
Math.max()
来比较并更新当前最大利润。
- 使用
知识点 | 说明 | 代码示例 |
---|---|---|
基本数据结构 | 使用数组来存储基本信息 | int[] difficulty, profit, worker; |
排序 | 对数组进行排序以便后续处理 | Arrays.sort(jobs, (a, b) -> a[0] - b[0]); |
贪心算法 | 对每个工人寻找他们能完成的收益最大的工作 | while (i < n && ability >= jobs[i][0]) { best = Math.max(best, jobs[i][1]); } |
循环控制 | 使用循环遍历数组、寻找条件满足的元素 | for (int ability : worker) { ... } |
变量管理 | 使用变量跟踪状态、存储中间计算结果 | int maxProfit = 0, i = 0, best = 0; |
逻辑运算 | 比较大小,计算最大值 | maxProfit += best; |