LeetCode 826. Most Profit Assigning Work

今天算法群里出的一道题,题目不难,但是这道题有多种解法,而且注意分析每种解法的时间复杂度,不能超时

题目:

We have jobs: difficulty[i] is the difficulty of the ith job, and profit[i] is the profit of the ith job.
Now we have some workers. worker[i] is the ability of the ith worker, which means that this worker can only complete a job with difficulty at most worker[i].
Every worker can be assigned at most one job, but one job can be completed multiple times.
For example, if 3 people attempt the same job that pays $1, then the total profit will be $3. If a worker cannot complete any job, his profit is $0.

What is the most profit we can make?

给定一些工作难度和每个工作的利润,以及每个工人能够完成的工作的最大难度,每个工人只能分配一个工作,到那时一个工作可以背多次完成,求怎么分配工作才能使得利润最大

分析:

  • 总的思路是贪心求解,会有O(n^3)的复杂度,关键是想着怎么减少复杂度,用TreeMap可以到复杂度O(n^2logn),优化下TreeMap能到O(nlogn),Sort+双指针的复杂度也是O(nlogn)

代码

  • 法一:暴力TreeMap---O(n^2logn)
public int maxProfitAssignment(int[] difficulty, int[] profit, int[] worker) {
        int res = 0;
        TreeMap<Integer, Integer> map = new TreeMap<>();
        for (int i = 0; i < difficulty.length; i++) {
            map.put(difficulty[i], i);
        }
        for (int w : worker) {
            Integer low = map.floorKey(w);
            if (low == null) continue;
            int index = map.get(low);
            for (int i = 0; i < difficulty.length; i++) {
                if (difficulty[i] <= low && profit[i] > profit[index]) {
                    index = i;
                } 
            }
            res += profit[index];
        }
        return res;
    }
  • 法二:优化的TreeMap---O(nlogn)
    • 如果TreeMap里面保存的是每个difficulty[i] 对应的最大的profit,则就可以直接找floorKey对应的value就是对应的要找的value;
      那么只需要再遍历一次TreeMap,将最大的到目前key位置最大的value放进去就行了
 public int maxProfitAssignment(int[] difficulty, int[] profit, int[] worker) {
        TreeMap<Integer, Integer> map = new TreeMap<>();
        for (int i = 0; i < difficulty.length; i++) {
            map.put(difficulty[i], Math.max(map.getOrDefault(difficulty[i], 0), profit[i]));
        }
        int max = 0;
        for (int key : map.keySet()) {  //将最大的到目前key位置最大的value放进去
            max = Math.max(max, map.get(key));
            map.put(key, max);
        }
        int res = 0;
        for (int w : worker) {
            Integer low = map.floorKey(w);
            if (low == null) continue;
            res += map.get(low);
        }
        return res;
    }
  • 法三:Sort + 双指针---O(nlogn)
    • 思路就是先将 difficulty和profit组成pair,然后再将list和worker 从小到大排序,然后遍历worker,更新tempMaxProfit,得到总的maxProfit
class Solution {
    public int maxProfitAssignment(int[] difficulty, int[] profit, int[] worker) {
        List<int[]> list = new ArrayList<>();
        for (int i = 0; i < difficulty.length; i++) {
            list.add(new int[]{difficulty[i], profit[i]});
        }
        Collections.sort(list, (a, b) -> {return a[0] - b[0];});
        Arrays.sort(worker);
        int res = 0, tmpMaxProfit = 0;
        //i, j同向双指针移动,更新到目前的tmpMaxProfit
        for (int i = 0, j = 0; i < worker.length; i++) {
            while (j < list.size() && list.get(j)[0] <= worker[i]) {
                tmpMaxProfit = Math.max(tmpMaxProfit, list.get(j)[1]);
                j++;
            }
            //此时tmpMaxProfit是前面所有difficulty小于worker[i]的最大的proifit
            res += tmpMaxProfit;
        }
        return res;
    }
    
}
原文地址:https://www.cnblogs.com/shawshawwan/p/10275911.html