【LeetCode】857. Minimum Cost to Hire K Workers

Problem Link

概览

给定N个工人,每个工人有一个quality值和一个wage值,要求在N个工人中雇佣K个人,并按照如下标准发放工资:

  • 每个人被发放的工资payquality的比值必须相同。
  • 每个人被发放的工资pay必须大于wage

求总工资的最小值。

题解

首先,对题目中的两个条件进行解读。

由题中第一个条件可知:

选定的K个人中,每人发放的实际工资payquality的比值相同。

定义价性比ratio = wage / quality,表达每个工人单位quality期望的工资,定义实际价性比ratio_ = pay / quality,那么由题中第二个条件可知:

选定的K个人中,每人发放的实际工资payquality的比值必须大于ratio

综上所述,可得本题关键性的信息:

选定的K个人中,ratio_ >= max{ratio},即实际价性比不得低于雇佣的工人中最高的期望价性比。

又因为总工资cost = ratio_ * sum(quality),所以要使得总工资尽可能的小,就要使ratio_sum(quality)尽可能小,因此可得具体的算法流程如下:

  1. 对所有人按价性比进行排序。
  2. 选择价性比最低的前K个人作为初始集,计算总工资。
  3. 从第K + 1个人开始,循环如下过程直至无人可以添加:
    1. 踢出原集合中quality最大的工人,并添加该新工人。
    2. 重新计算quality的总和。
    3. 重新计算总工资,若小于当前最小值,则更新该值。

上述算法本质即遍历所有可能的价性比,找出最小的总工资。

复杂度分析

本题的空间复杂度为$O(N)$,但时间复杂度并不那么直观,需要逐步分析。

  1. 对所有人的价性比进行排序。($O(NlogN)$)
  2. 选择价性比最低的前K个人作为初始集,计算总工资。($O(N)$)
  3. 从第K + 1个人开始,循环如下过程直至无人可以添加:($O(N)$)
    1. 踢出原集合中quality最大的工人,并添加该新工人。($O(logN)$)
    2. 重新计算quality的总和。($O(1)$)
    3. 重新计算总工资,若小于当前最小值,则更新该值。($O(1)$)

其中步骤3.1的复杂度依赖于具体实现方式,使用优先队列实现可以保证复杂度为$O(logN)$。

步骤3.2只需要取出踢出的工人和新工人的quality值即可计算,复杂度为常数时间。

步骤3.3中用新工人的ratio作为总ratio_进行计算,复杂度为常数时间。

综上所述,时间复杂度为$O(NlogN)$,空间复杂度为$O(N)$。

附录

我的解答