题目:
有 n
名工人。 给定两个数组 quality
和 wage
,其中,quality[i]
表示第 i
名工人的工作质量,其最低期望工资为 wage[i]
。
现在我们想雇佣 k
名工人组成一个工资组。在雇佣 一组 k
名工人时,我们必须按照下述规则向他们支付工资:
- 对工资组中的每名工人,应当按其工作质量与同组其他工人的工作质量的比例来支付工资。
- 工资组中的每名工人至少应当得到他们的最低期望工资。
给定整数 k
,返回 组成满足上述条件的付费群体所需的最小金额 。在实际答案的 10^-5
以内的答案将被接受。
提示:
n == quality.length == wage.length
1 <= k <= n <= 104
1 <= quality[i], wage[i] <= 104
思考:
暴力解法
由题意可知,一定至少有一个人(i)发的工资正好等于期待的工资wage[i],那么其他人(x)发的工资按比例即为:,同时发的工资要满足大于等于wage[x]的条件。将满足条件的实发工资从小到大排序,前k个之和即为选的k个人的工资和sum,遍历i得到的sum的最小值即为答案。代码如下:
class Solution:
def mincostToHireWorkers(self, quality: List[int], wage: List[int], k: int) -> float:
n = len(quality)
sum_dict = {}
for i in range(n):
pay = []
for x in range(n):
pay_x = wage[i] / quality[i] * quality[x] # 按比例实发工资
if pay_x >= wage[x]: # 实发工资大于等于期望工资则加入候选
pay.append(pay_x)
if len(pay) >= k:
# 若满足条件不足k人,则跳到下一人;否则排序,取前k个工资之和
pay.sort()
sum_dict[i] = sum(pay[:k])
return min(sum_dict.values())
超时,卡在第 41 / 46 个例子:
优化 ——最小堆
代码如下,思路在注释里:
class Solution:
def mincostToHireWorkers(self, quality: List[int], wage: List[int], k: int) -> float:
n = len(wage)
candidates = sorted(zip(wage, quality), key = lambda candidate:candidate[0]/candidate[1]) # 按r=wage/quality从小到大排序
ans = float('inf')
for i in range(k-1, n):
r = candidates[i][0]/candidates[i][1] # 基准r
Q = candidates[i][1] # quality之和,初始化为i的quality
# 当前考虑的 candidate 列表的前 i 个元素
current_candidates = candidates[:i]
# 获取这些元素的 quality 并创建一个最小堆
qualities = [qual for _, qual in current_candidates]
heapq.heapify(qualities)
# 取最小的 k-1 个 quality 的和,加给Q
Q += sum(heapq.nsmallest(k-1, qualities))
res = Q * r
if res < ans:
ans = res
return ans
但是还是不够快,这里参考灵神的写法:
class Solution:
def mincostToHireWorkers(self, quality: List[int], wage: List[int], k: int) -> float:
pairs = sorted(zip(quality, wage), key=lambda p: p[1] / p[0]) # 按照 r 值排序
h = [-q for q, _ in pairs[:k]] # 加负号变成最大堆
heapify(h)
sum_q = -sum(h)
ans = sum_q * pairs[k - 1][1] / pairs[k - 1][0] # 选 r 值最小的 k 名工人
for q, w in pairs[k:]: # 后面的工人 r 值更大
if q < -h[0]: # 但是 sum_q 可以变小,从而可能得到更优的答案
sum_q += heapreplace(h, -q) + q # 更新堆顶和 sum_q
ans = min(ans, sum_q * w / q)
return ans
作者:灵茶山艾府
链接:https://leetcode.cn/problems/minimum-cost-to-hire-k-workers/solutions/1815856/yi-bu-bu-ti-shi-ru-he-si-kao-ci-ti-by-en-1p00/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
T T算法之路漫漫啊,提交通过: