LeetCode[Hard]------857. Minimum Cost To Hire K Workers
問題描述
There are N workers. The i-th worker has a quality[i] and a minimum wage expectation wage[i].
Now we want to hire exactly K workers to form a paid group. When hiring a group of K workers, we must pay them according to the following rules:
- Every worker in the paid group should be paid in the ratio of their quality compared to other workers in the paid group.
- Every worker in the paid group must be paid at least their minimum wage expectation.
Return the least amount of money needed to form a paid group satisfying the above conditions.
Example 1:
Input: quality = [10,20,5], wage = [70,50,30], K = 2 Output: 105.00000 Explanation: We pay 70 to 0-th worker and 35 to 2-th worker.
Example 2:
Input: quality = [3,1,10,10,1], wage = [4,8,2,2,7], K = 3 Output: 30.66667 Explanation: We pay 4 to 0-th worker, 13.33333 to 2-th and 3-th workers seperately.
簡單翻譯一下,現在要僱傭K名工人,每個工人有自己的能力值quality和對期望的薪水wage,但是他們實際的薪水必須滿足兩個條件
- 實際薪水必須和他們的能力成正比。
- 每個被僱傭的工人必須滿足他們最低的薪水期望
要求返回僱傭K個工人最小的支付薪水。
思路:
首先要對題目所給的rules有精確的理解,簡單來說就是1份quality,1份wage,而且每個人都有滿足其最小wage expectation。
我的第一印象是按wage大小對workers進行排序,把最小的K個wage的加起來即可,因為題目中沒有對quality的限制。但這麼想的話根本就是個easy問題。再三考慮之後發現,發錢時並不是按wage陣列發的,而是和wage/quality這個比值有關。因為根據rule1,worker i,j 的quality[i]:quality[j] == wage[i]: wage[j]的,因此 quality[i]:wage[i] == quality[j]:wage[j],也就是說wage/quality 的ratio對於每個worker來說都一樣!!
於是我有了思路,通過這個ratio構建worker陣列,並從小到大sort,然後我們取前K個worker,他們的ratio必須是ratio最大的那個 worker的,也就是最近取的那個worker,此時的wage總和就是總的quality × 最近取的worker的ratio。
做到這裡感覺程式就可以結束了,因為ratio這裡是最小的。但是如果我們繼續遍歷worker,ratio雖然增大但是quality的總和可能會減小。所以我們需要遍歷所有worker,保證hire window的size始終為K。
問題又來了,如何保證K個worker的quality在遍歷時持續remove最大的quality? PriorityQueue 可以完美解決這個問題,只需要add進負的worker quality,此時poll出的就是最大的quality。
程式碼:
public double mincostToHireWorkers(int[] quality, int[] wage, int K) {
double[][] workers = new double[quality.length][2];
for (int i = 0; i < quality.length; ++i)
workers[i] = new double[]{(double)(wage[i]) / quality[i], (double)quality[i]};
Arrays.sort(workers, (a, b) -> Double.compare(a[0], b[0]));
double res = Double.MAX_VALUE, qsum = 0;
PriorityQueue<Double> l = new PriorityQueue<>();
for (double[] worker: workers) {
qsum += worker[1];
l.add(-worker[1]);
if (l.size() > K) qsum += l.poll();
if (l.size() == K) res = Math.min(res, qsum * worker[0]);
}
return res;
}