zoukankan      html  css  js  c++  java
  • leetcode 826

    题目描述

    有一些工作:difficulty[i] 表示第i个工作的难度,profit[i]表示第i个工作的收益。

    现在我们有一些工人。worker[i]是第i个工人的能力,即该工人只能完成难度小于等于worker[i]的工作。

    每一个工人都最多只能安排一个工作,但是一个工作可以完成多次。

    举个例子,如果3个工人都尝试完成一份报酬为1的同样工作,那么总收益为 $3。如果一个工人不能完成任何工作,他的收益为 $0 。

    我们能得到的最大收益是多少?

    示例:

    输入: 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] 的收益。
    提示:

    1 <= difficulty.length = profit.length <= 10000
    1 <= worker.length <= 10000
    difficulty[i], profit[i], worker[i]  的范围是 [1, 10^5]

    思路及代码

    beat 80%

    public class Solution {
        public int maxProfitAssignment(int[] difficulty, int[] profit, int[] worker) {
            // map建立difficult与profit的一一对应关系
            Map<Integer, Integer> map = new HashMap<>();
            for (int d = 0; d < difficulty.length; d++) {
                Integer p = map.get(difficulty[d]);
                if (p == null){
                    map.put(difficulty[d], profit[d]);
                } else {
                    map.put(difficulty[d], Math.max(p,profit[d]));
                }
            }
            /*
            因为能做困难度大的工人肯定能做困难度小的工作,所以按照困难度从小到大的顺序处理一遍map中difficult与profit的对应关系。
            使得做困难度大的工作的收益要大于比它困难度小的工作的收益。
             */
            Arrays.sort(difficulty);
            for (int i = 1; i < difficulty.length; i++) {
                if (difficulty[i] == difficulty[i-1]) continue;
                if (map.get(difficulty[i]) < map.get(difficulty[i-1])) {
                    map.put(difficulty[i], map.get(difficulty[i-1]));
                }
            }
            /*
            将difficult和worker从小到大排序,利用两个指针从小到大进行对应难度对应收益的查找。
             */
            int res = 0;
            Arrays.sort(worker);
            int w = 0, d = 0;
            while (w < worker.length){
                while (d < difficulty.length && worker[w] >= difficulty[d]) ++d;
                if (d-1 >= 0)
                    res += map.get(difficulty[d-1]);
                ++w;
            }
            return res;
        }
    
        public static void main(String[] args) {
            int[] d = {85,47,57};
            int[] p = {24,66,99};
            int[] w = {40,25,25};
            int i = new Solution().maxProfitAssignment(d, p, w);
            System.out.println("i = " + i);
        }
    }
    

    题解

    方法:排序
    想法

    我们可以以任意顺序考虑工人,所以我们按照能力大小排序。

    如果我们先访问低难度的工作,那么收益一定是截至目前最好的。

    算法

    我们使用 “双指针” 的方法去安排任务。我们记录最大可用利润 best。对于每个能力值为 skill 的工人,找到难度小于等于能力值的任务,并将如结果中。

    import java.awt.Point;
    
    class Solution {
        public int maxProfitAssignment(int[] difficulty, int[] profit, int[] worker) {
            int N = difficulty.length;
            Point[] jobs = new Point[N];
            for (int i = 0; i < N; ++i)
                jobs[i] = new Point(difficulty[i], profit[i]);
            Arrays.sort(jobs, (a, b) -> a.x - b.x);
            Arrays.sort(worker);
    
            int ans = 0, i = 0, best = 0;
            for (int skill: worker) {
                while (i < N && skill >= jobs[i].x)
                    best = Math.max(best, jobs[i++].y);
                ans += best;
            }
    
            return ans;
        }
    }
    

    复杂度分析

    • 时间复杂度:$O(NlogN+QlogQ)$,其中 N 是任务个数,Q 是工人数量。
    • 空间复杂度:$O(N)$,jobs 的额外空间。

    我的收获

    • java.awt.Point的使用
    • 对Point对象进行排序的扫操作:Arrays.sort(jobs, (a, b) -> a.x - b.x);
  • 相关阅读:
    Leetcode 811. Subdomain Visit Count
    Leetcode 70. Climbing Stairs
    Leetcode 509. Fibonacci Number
    Leetcode 771. Jewels and Stones
    Leetcode 217. Contains Duplicate
    MYSQL安装第三步报错
    .net 开发WEB程序
    JDK版本问题
    打开ECLIPSE 报failed to load the jni shared library
    ANSI_NULLS SQL语句
  • 原文地址:https://www.cnblogs.com/yfs123456/p/11870874.html
Copyright © 2011-2022 走看看