夯实算法-安排工作以达到最大收益

172 阅读1分钟

题目:安排工作以达到最大收益

你有 n 个工作和 m 个工人。给定三个数组: difficultyprofit 和 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]<=1051 <= difficulty[i], profit[i], worker[i] <= 10^5

解题思路

因为需要收益获得最大, 所以在有能力的情况下肯定是希望获得的利益越大越好,利益相同的时候难度越小越好。 基于此 先将工作难度以及对应的利益进行排序,首先根据利益从大到小排序,当利益相同时根据难度从小到大排序。 然后对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!