题目:安排工作以达到最大收益
你有 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.lengthn == profit.lengthm == worker.length1 <= n, m <= 104
解题思路
因为需要收益获得最大, 所以在有能力的情况下肯定是希望获得的利益越大越好,利益相同的时候难度越小越好。 基于此 先将工作难度以及对应的利益进行排序,首先根据利益从大到小排序,当利益相同时根据难度从小到大排序。 然后对worker进行从小到大排序L指针指向能力最弱的工人,R指针指向能力最强的工人,
如果L位置的工人可以完成当前任务,因为任务已经重新排序利益必是当前能够获得的最大利益,尝试让L位置的工人完成当前任务,并且加上获利 如果L位置的工人不可以完成当前任务, 尝试让R位置的工人完成当前任务,并且加上获利 如果两个位置上的工人都无法完成当前任务 只能将获利减少 尝试下一个获利最大任务难度最低的任务
如果难度越大,收益越高,只要对difficulty进行排序,再对它进行二分,找到最后一个小于等于工人能力的难度,取对应的收益,就是这个工人能找到的最好工作
但是题目并没有这个限制,难度大,收益反而可能低,所以我们把这一点限制加上去。
变成:对于任意一个难度,找到小于等于这个难度的收益的最大值,用这个最大值覆盖掉当前难度对应的收益,这样就保证了难度越大,收益越高
代码实现
public int maxProfitAssignment(int[] difficulty, int[] profit, int[] worker) {
int n = difficulty.length, m = worker.length;
int[][] a = new int[n][2];
for (int i = 0; i < n; i++) {
a[i][0] = difficulty[i];
a[i][1] = profit[i];
}
Arrays.sort(a, new Comparator < int[] > () {@
Override
public int compare(int[] o1, int[] o2) {
// 如果难度不同,则按难度升序排序;如果难度相同,则按收益升序排序
if (o1[0] == o2[0]) return o1[1] - o2[1];
else return o1[0] - o2[0];
}
});
int[] maxProfit = new int[100001];
int nowProfit = 0;
for (int i = 0; i < n - 1; i++) {
int j = a[i][0];
nowProfit = Math.max(nowProfit, a[i][1]);
while (j < a[i + 1][0]) {
maxProfit[j] = nowProfit;
j++;
}
}
int j = a[n - 1][0];
nowProfit = Math.max(nowProfit, a[n - 1][1]);
while (j <= 100000) {
maxProfit[j] = nowProfit;
j++;
}
int ans = 0;
for (int w: worker) {
ans += maxProfit[w];
}
return ans;
}
运行结果
复杂度分析
- 空间复杂度:O(n)
- 时间复杂度:O(n)
在掘金(JUEJIN) 一起分享知识, Keep Learning!