LC每日一题|20240502 - 857. 雇佣 K 名工人的最低成本

103 阅读2分钟

LC每日一题|20240502 - 857. 雇佣 K 名工人的最低成本

n 名工人。 给定两个数组 quality 和 wage ,其中,quality[i] 表示第 i 名工人的工作质量,其最低期望工资为 wage[i] 。

现在我们想雇佣 k 名工人组成一个工资组。 在雇佣 一组 k 名工人时,我们必须按照下述规则向他们支付工资:

  1. 对工资组中的每名工人,应当按其工作质量与同组其他工人的工作质量的比例来支付工资。
  2. 工资组中的每名工人至少应当得到他们的最低期望工资。

给定整数 k ,返回 组成满足上述条件的付费群体所需的最小金额 。在实际答案的 10^-5 以内的答案将被接受。

提示:

  • n == quality.length == wage.length
  • 1 <= k <= n <= 10^4
  • 1 <= quality[i], wage[i] <= 10^4

题目等级:Hard

解题思路

友情提示,千万不要把你自己带入到这道题中,小心血压⬆️ ⬆️ ⬆️。

由于题目中说工资是按照工作质量成比例发放的,所以最终每个人所拿到的单位薪资,即 cost / quality,是相同的。就此我们可以得知,对于任意一组工人来说,所付金额 = 组内所有人的质量和 * 其中性价比最低者的单位薪资

我们可以先处理出每个工人期望的单位薪资,开一个小顶堆进行排序(实际上就是性价比的反序)。然后再用一个小顶堆维护组内每个人的质量,每次加入一个新人的时候,都将原有的质量最高的老人踢出去因为他们花钱最多。最后动态维护所付金额的最小值返回即可。

AC代码

class Solution {
    fun mincostToHireWorkers(quality: IntArray, wage: IntArray, k: Int): Double {
        val vc = DoubleArray(quality.size) { 1.0 * wage[it] / quality[it] }
        val v = PriorityQueue<Int>() { a, b -> vc[a].compareTo(vc[b]) }
        val qq = PriorityQueue<Int>() { a, b -> quality[b] - quality[a] }
        for (i in quality.indices) v.offer(i)
        var sumQuality = 0
        var minResult = Double.MAX_VALUE
        var poll = 0
        repeat(k) {
            poll = v.poll()
            sumQuality += quality[poll]
            qq.offer(poll)
        }
        var min = sumQuality * vc[poll]
        for (i in k until quality.size) {
            poll = v.poll()
            qq.offer(poll)
            val qp = qq.poll()
            sumQuality -= quality[qp]
            sumQuality += quality[poll]
            min = Math.min(min, sumQuality * vc[poll])
        }
        return min
    }
}

时间复杂度:O(nlogn),用于堆排序。

空间复杂度:O(n),需要维护两个堆。

碎碎念

这个资本家根本不关心这帮人能做多少东西,他只关注三件事情:

  • 少花钱
  • 凑人头
  • 防内斗

(是不是有点像你的leader?

请不要对号入座,如有雷同,实属巧合~