leetcode
leetcode 751 ~ 800
雇佣 K 名工人的最低成本

雇佣 K 名工人的最低成本

难度:

标签:

题目描述

代码结果

运行时间: 55 ms, 内存: 18.1 MB


/*
 * Problem: Given n workers, each worker has a certain quality and a minimum expected wage. 
 * We want to hire k workers such that we minimize the total amount of money paid. 
 * We must pay each worker based on the ratio of their quality to other workers' quality, 
 * and each worker must receive at least their minimum expected wage.
 * 
 * Solution Approach: 
 * 1. Calculate the ratio of wage[i] / quality[i] for each worker and sort them by this ratio.
 * 2. Use a priority queue to maintain the smallest k quality workers.
 * 3. For each worker, calculate the total wage needed if they are the highest ratio worker.
 * 4. Track the minimum total wage.
 */

import java.util.*;
import java.util.stream.*;

public class Solution {
    public double mincostToHireWorkers(int[] quality, int[] wage, int k) {
        // Create a list of Worker objects and sort by the ratio of wage/quality
        List<Worker> workers = IntStream.range(0, quality.length)
                .mapToObj(i -> new Worker(quality[i], wage[i]))
                .sorted(Comparator.comparingDouble(worker -> worker.ratio))
                .collect(Collectors.toList());

        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder());
        double totalQuality = 0.0;
        double result = Double.MAX_VALUE;
        // Iterate through workers and maintain the smallest k quality workers
        for (Worker worker : workers) {
            totalQuality += worker.quality;
            maxHeap.add(worker.quality);
            if (maxHeap.size() > k) {
                totalQuality -= maxHeap.poll();
            }
            if (maxHeap.size() == k) {
                result = Math.min(result, totalQuality * worker.ratio);
            }
        }
        return result;
    }

    class Worker {
        int quality;
        int wage;
        double ratio;

        Worker(int quality, int wage) {
            this.quality = quality;
            this.wage = wage;
            this.ratio = (double) wage / quality;
        }
    }
}

解释

方法:

此题的关键是如何以最低成本雇佣k名工人。要求每名工人的工资与他们的工作质量成比例,且不低于他们的最低期望工资。首先,我们需要确定支付给每位工人的单位工资(即工资与质量的比率)。题解中采用了一个贪心策略,按照每位工人的单位工资从高到低排序。然后使用一个最大堆来维护当前选择的工人的质量总和,堆的大小维持为k-1,这样可以在添加新的工人时,快速计算出增加的总成本。对于每个工人,计算包括他在内的k个工人的总成本,并更新最小成本。最小成本是通过当前工人的期望工资加上其他k-1个工人的工资总和(由单位工资乘以他们的质量总和得到)来计算。

时间复杂度:

O(n log n)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么根据每位工人的单位工资(工资/质量比)从高到低进行排序?这种排序方式对解题有什么帮助?
按照单位工资从高到低进行排序可以帮助我们在遍历工人时,始终保持当下正在考虑的工人有最低的单位工资。这种方式有效地将问题转化为:一旦选定了某个工人作为单位工资的基准(即当前遍历到的工人),只需要考虑如何以此单位工资最小化其他工人的成本。这样可以确保在满足k个工人的条件下,总成本尽可能低,因为随着遍历的进行,单位工资会逐渐减小,我们只需要关注在这个单位工资下,如何选择其他k-1个工人使得成本最低。
🦆
代码中的最大堆用来维护什么数据,为何选择最大堆而不是最小堆?
最大堆在此代码中用来维护当前选择的k-1个工人的质量。使用最大堆的原因是,当我们需要添加一个新工人到已经选定的k-1个工人中时,我们可能需要替换掉其中某个工人以保证总成本最低。最大堆允许我们快速识别出当前质量最大的工人(即堆顶元素),并在必要时将其替换出去,这样可以确保我们总是尽可能地减少质量总和,从而在给定的单位工资下最小化总成本。
🦆
在解法中,为什么要在初始化堆时只添加k-1个工人的质量?添加k个工人的质量会有什么不同的结果?
在初始化堆时只添加k-1个工人的质量,是为了在后续的迭代中方便地计算包括当前考虑的工人在内的总成本。如果堆中已经包含了k-1个工人的质量,当考虑一个新的工人时,只需将这个新工人的质量加到堆的质量总和中,就可以直接计算出包括这个新工人在内的k个工人的总成本。如果堆中已经有k个工人的质量,那么每次考虑新工人时,我们不仅需要添加这个新工人的质量,还必须从堆中移除一个工人的质量,这将增加额外的复杂度和运算量。

相关问题