原文链接: https://leetcode-cn.com/problems/minimum-cost-to-hire-k-workers
英文原文
There are n
workers. You are given two integer arrays quality
and wage
where quality[i]
is the quality of the ith
worker and wage[i]
is the minimum wage expectation for the ith
worker.
We want to hire exactly k
workers to form a paid group. To hire 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.
Given the integer k
, return the least amount of money needed to form a paid group satisfying the above conditions. Answers within 10-5
of the actual answer will be accepted.
Example 1:
Input: quality = [10,20,5], wage = [70,50,30], k = 2 Output: 105.00000 Explanation: We pay 70 to 0th worker and 35 to 2nd 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 0th worker, 13.33333 to 2nd and 3rd workers separately.
Constraints:
n == quality.length == wage.length
1 <= k <= n <= 104
1 <= quality[i], wage[i] <= 104
中文题目
有 N
名工人。 第 i
名工人的工作质量为 quality[i]
,其最低期望工资为 wage[i]
。
现在我们想雇佣 K
名工人组成一个工资组。在雇佣 一组 K 名工人时,我们必须按照下述规则向他们支付工资:
- 对工资组中的每名工人,应当按其工作质量与同组其他工人的工作质量的比例来支付工资。
- 工资组中的每名工人至少应当得到他们的最低期望工资。
返回组成一个满足上述条件的工资组至少需要多少钱。
示例 1:
输入: quality = [10,20,5], wage = [70,50,30], K = 2 输出: 105.00000 解释: 我们向 0 号工人支付 70,向 2 号工人支付 35。
示例 2:
输入: quality = [3,1,10,10,1], wage = [4,8,2,2,7], K = 3 输出: 30.66667 解释: 我们向 0 号工人支付 4,向 2 号和 3 号分别支付 13.33333。
提示:
1 <= K <= N <= 10000
,其中N = quality.length = wage.length
1 <= quality[i] <= 10000
1 <= wage[i] <= 10000
- 与正确答案误差在
10^-5
之内的答案将被视为正确的。
通过代码
官方题解
方法一:贪心
显然,当我们选择 K
名工人时,会只要有一名工人恰好拿到了他的最低期望工资。因此,我们可以枚举是哪一名工人恰好拿到了他的最低期望工资,并检查在当前的“工资/质量”比值下,其他工人拿到的工资是否不少于他们的最低期望工资。如果有至少 K - 1
名工人满足条件,那么我们就在这些工人中选出 K - 1
名拿到工资最低的,加上枚举的那一名工人的最低期望工资,就得到了一个答案。在所有的答案中,返回最小值。
注意这种方法可能会超出时间限制。
[sol1]class Solution { public double mincostToHireWorkers(int[] quality, int[] wage, int K) { int N = quality.length; double ans = 1e9; for (int captain = 0; captain < N; ++captain) { // Must pay at least wage[captain] / quality[captain] per qual double factor = (double) wage[captain] / quality[captain]; double prices[] = new double[N]; int t = 0; for (int worker = 0; worker < N; ++worker) { double price = factor * quality[worker]; if (price < wage[worker]) continue; prices[t++] = price; } if (t < K) continue; Arrays.sort(prices, 0, t); double cand = 0; for (int i = 0; i < K; ++i) cand += prices[i]; ans = Math.min(ans, cand); } return ans; } }
[sol1]class Solution(object): def mincostToHireWorkers(self, quality, wage, K): from fractions import Fraction ans = float('inf') N = len(quality) for captain in xrange(N): # Must pay at least wage[captain] / quality[captain] per qual factor = Fraction(wage[captain], quality[captain]) prices = [] for worker in xrange(N): price = factor * quality[worker] if price < wage[worker]: continue prices.append(price) if len(prices) < K: continue prices.sort() ans = min(ans, sum(prices[:K])) return float(ans)
复杂度分析
时间复杂度:$O(N^2 \log N)$。
空间复杂度:$O(N)$。
方法二:堆(优先队列)
在方法一中,我们枚举了一名工人,并对剩下的工人计算对应的工资,并选出 K - 1
个工资最低的进行累加。事实上,我们可以定义一个“价值”,表示工人最低期望工资与工作质量之比。例如某位工人的最低期望工资为 100
,工作质量为 20
,那么他的价值为 100 / 20 = 5.0
。
可以发现,如果一名工人的价值为 R
,当他恰好拿到最低期望工资时,如果所有价值高于 R
的工人都无法拿到最低期望工资,而所有价值低于 R
的工人都拿得比最低期望工资多。因此,我们可以按照这些工人的价值,对他们进行升序排序。排序后的第 i
名工人可以在它之前任选 K - 1
名工人,并计算对应的工资总和,为 R * sum(quality[c1] + quality[c2] + ... + quality[c{k-1}] + quality[i])
,也就是说,我们需要在前 i
名工人中选择 K
个工作质量最低的。我们可以使用一个大根堆来实时维护 K
个最小值。
[sol2]class Solution { public double mincostToHireWorkers(int[] quality, int[] wage, int K) { int N = quality.length; Worker[] workers = new Worker[N]; for (int i = 0; i < N; ++i) workers[i] = new Worker(quality[i], wage[i]); Arrays.sort(workers); double ans = 1e9; int sumq = 0; PriorityQueue<Integer> pool = new PriorityQueue(); for (Worker worker: workers) { pool.offer(-worker.quality); sumq += worker.quality; if (pool.size() > K) sumq += pool.poll(); if (pool.size() == K) ans = Math.min(ans, sumq * worker.ratio()); } return ans; } } class Worker implements Comparable<Worker> { public int quality, wage; public Worker(int q, int w) { quality = q; wage = w; } public double ratio() { return (double) wage / quality; } public int compareTo(Worker other) { return Double.compare(ratio(), other.ratio()); } }
[sol2]class Solution(object): def mincostToHireWorkers(self, quality, wage, K): from fractions import Fraction workers = sorted((Fraction(w, q), q, w) for q, w in zip(quality, wage)) ans = float('inf') pool = [] sumq = 0 for ratio, q, w in workers: heapq.heappush(pool, -q) sumq += q if len(pool) > K: sumq += heapq.heappop(pool) if len(pool) == K: ans = min(ans, ratio * sumq) return float(ans)
复杂度分析
时间复杂度:$O(N \log N)$。
空间复杂度:$O(N)$。
统计信息
通过次数 | 提交次数 | AC比率 |
---|---|---|
3198 | 6821 | 46.9% |
提交历史
提交时间 | 提交结果 | 执行时间 | 内存消耗 | 语言 |
---|