LeetCode 题解工作台
雇佣 K 位工人的总代价
给你一个下标从 0 开始的整数数组 costs ,其中 costs[i] 是雇佣第 i 位工人的代价。 同时给你两个整数 k 和 candidates 。我们想根据以下规则恰好雇佣 k 位工人: 总共进行 k 轮雇佣,且每一轮恰好雇佣一位工人。 在每一轮雇佣中,从最前面 candidates 和最后…
4
题型
5
代码语言
3
相关题
当前训练重点
中等 · 双·指针·invariant
答案摘要
我们首先判断 $candidates \times 2$ 是否大于等于 ,如果是,我们直接返回前 个最小的工人的代价之和。 否则,我们使用一个小根堆 来维护前 个工人和后 个工人的代价。
Interview AiBoxInterview AiBox 实时 AI 助手,陪你讲清 双·指针·invariant 题型思路
题目描述
给你一个下标从 0 开始的整数数组 costs ,其中 costs[i] 是雇佣第 i 位工人的代价。
同时给你两个整数 k 和 candidates 。我们想根据以下规则恰好雇佣 k 位工人:
- 总共进行
k轮雇佣,且每一轮恰好雇佣一位工人。 - 在每一轮雇佣中,从最前面
candidates和最后面candidates人中选出代价最小的一位工人,如果有多位代价相同且最小的工人,选择下标更小的一位工人。- 比方说,
costs = [3,2,7,7,1,2]且candidates = 2,第一轮雇佣中,我们选择第4位工人,因为他的代价最小[3,2,7,7,1,2]。 - 第二轮雇佣,我们选择第
1位工人,因为他们的代价与第4位工人一样都是最小代价,而且下标更小,[3,2,7,7,2]。注意每一轮雇佣后,剩余工人的下标可能会发生变化。
- 比方说,
- 如果剩余员工数目不足
candidates人,那么下一轮雇佣他们中代价最小的一人,如果有多位代价相同且最小的工人,选择下标更小的一位工人。 - 一位工人只能被选择一次。
返回雇佣恰好 k 位工人的总代价。
示例 1:
输入:costs = [17,12,10,2,7,2,11,20,8], k = 3, candidates = 4 输出:11 解释:我们总共雇佣 3 位工人。总代价一开始为 0 。 - 第一轮雇佣,我们从 [17,12,10,2,7,2,11,20,8] 中选择。最小代价是 2 ,有两位工人,我们选择下标更小的一位工人,即第 3 位工人。总代价是 0 + 2 = 2 。 - 第二轮雇佣,我们从 [17,12,10,7,2,11,20,8] 中选择。最小代价是 2 ,下标为 4 ,总代价是 2 + 2 = 4 。 - 第三轮雇佣,我们从 [17,12,10,7,11,20,8] 中选择,最小代价是 7 ,下标为 3 ,总代价是 4 + 7 = 11 。注意下标为 3 的工人同时在最前面和最后面 4 位工人中。 总雇佣代价是 11 。
示例 2:
输入:costs = [1,2,4,1], k = 3, candidates = 3 输出:4 解释:我们总共雇佣 3 位工人。总代价一开始为 0 。 - 第一轮雇佣,我们从 [1,2,4,1] 中选择。最小代价为 1 ,有两位工人,我们选择下标更小的一位工人,即第 0 位工人,总代价是 0 + 1 = 1 。注意,下标为 1 和 2 的工人同时在最前面和最后面 3 位工人中。 - 第二轮雇佣,我们从 [2,4,1] 中选择。最小代价为 1 ,下标为 2 ,总代价是 1 + 1 = 2 。 - 第三轮雇佣,少于 3 位工人,我们从剩余工人 [2,4] 中选择。最小代价是 2 ,下标为 0 。总代价为 2 + 2 = 4 。 总雇佣代价是 4 。
提示:
1 <= costs.length <= 1051 <= costs[i] <= 1051 <= k, candidates <= costs.length
解题思路
方法一:优先队列(小根堆)
我们首先判断 是否大于等于 ,如果是,我们直接返回前 个最小的工人的代价之和。
否则,我们使用一个小根堆 来维护前 个工人和后 个工人的代价。
我们首先将前 个工人的代价以及对应的下标加入小根堆 中,然后将后 个工人的代价以及对应的下标加入小根堆 中。用两个指针 和 分别指向前后待选工人的下标,初始时 , 。
然后我们进行 次循环,每次从小根堆 中取出代价最小的工人,将其代价加入答案,如果 ,说明前后待选工人已经全部被选完,直接跳过。否则,如果当前工人的下标小于 ,说明是前面的工人,我们将第 个工人的代价以及下标加入小根堆 中,然后 加一;否则,我们将第 个工人的代价以及下标加入小根堆 中,然后 减一。
循环结束后,返回答案即可。
时间复杂度 ,空间复杂度 。其中 是数组 的长度。
class Solution:
def totalCost(self, costs: List[int], k: int, candidates: int) -> int:
n = len(costs)
if candidates * 2 >= n:
return sum(sorted(costs)[:k])
pq = []
for i, c in enumerate(costs[:candidates]):
heappush(pq, (c, i))
for i in range(n - candidates, n):
heappush(pq, (costs[i], i))
heapify(pq)
l, r = candidates, n - candidates - 1
ans = 0
for _ in range(k):
c, i = heappop(pq)
ans += c
if l > r:
continue
if i < l:
heappush(pq, (costs[l], l))
l += 1
else:
heappush(pq, (costs[r], r))
r -= 1
return ans
复杂度分析
| 指标 | 值 |
|---|---|
| 时间 | O((k + m) \cdot\log m) |
| 空间 | O(m) |
面试官常问的追问
外企场景- question_mark
Candidate should understand the two-pointer approach and the use of minheaps in optimization problems.
- question_mark
Look for candidates who are comfortable with tracking invariant conditions across array segments.
- question_mark
Watch for the ability to efficiently calculate costs using heaps without unnecessary comparisons.
常见陷阱
外企场景- error
Failing to maintain the invariant that the two pointers represent valid candidate ranges for selection.
- error
Using only one heap and not considering the left and right parts of the array efficiently.
- error
Not optimizing the heap operations, leading to suboptimal performance.
进阶变体
外企场景- arrow_right_alt
Consider different candidate ranges (not just two sides of the array) for more complex scenarios.
- arrow_right_alt
Use a single heap in certain cases to test if a simpler solution might be more efficient for smaller input sizes.
- arrow_right_alt
Introduce variations where the workers are ordered differently to test the efficiency of heap-based approaches.