LC每日一题|20240501 - 2462. 雇佣 K 位工人的总代价

70 阅读2分钟

LC每日一题|20240501 - 2462. 雇佣 K 位工人的总代价

给你一个下标从 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.length <= 10^5
  • 1 <= costs[i] <= 10^5
  • 1 <= k, candidates <= costs.length

题目等级:Medium

解题思路

我们仅需要维护一个小顶堆用以获取每轮受雇的工人,同时动态维护雇佣工人的左右边界即可,需要时刻保证左右边界不能碰撞。

AC代码

class Solution {
    fun totalCost(costs: IntArray, k: Int, candidates: Int): Long {
        val q = PriorityQueue<IntArray>() { a, b -> if (a[0] == b[0]) a[1] - b[1] else a[0] - b[0] }
        var left = -1
        var right = costs.size
        repeat(candidates) {
            if (right > left + 1) q.offer(intArrayOf(costs[++left], left))
            if (right > left + 1) q.offer(intArrayOf(costs[--right], right))
        }
        
        var res = 0L
        repeat(k) {
            val poll = q.poll() 
            res += poll[0]
            if (left < right - 1) {
                if (poll[1] <= left) q.offer(intArrayOf(costs[++left], left))
                if (poll[1] >= right) q.offer(intArrayOf(costs[--right], right))
            }
        }
        return res
    }
}

时间复杂度:O((k + candidates) log candidates),需要取最多(k + candidates)个元素,同时需要在candidates个元素中取其中最小的元素。

空间复杂度:O(candidates),固定为candidates个元素大小的堆。

碎碎念

劳动节?资本家节!