2024-5-2
题目来源
我的题解
方法一 贪心+优先队列
参考灵神
关键点1:只有有一个工人刚好获得其最低期望薪资。因为,若所有工人都获得比自己最低期望薪资高,那么可以降低工人工资以实现更低的成本。
关键点2:找到,工人i的工作效率r=wage[i]/quality[i],若以某人的 r i r_i ri为基准发工资,那么对于 r 值不超过 r i r_i ri的工人,发给他们的工资是不低于其最低期望工资的,因此这些工人是可以随意选择(雇佣)的
关键点3:如何在从小到大枚举 r i r_i ri时,维护当前最小的 k 个 quality 值?使用最大堆来维护。按照 r i r_i ri从小到大的顺序遍历工人,当堆中有 k 个元素时,如果 qualityi比堆顶小,则可以弹出堆顶,将 quality i \textit{quality}_i qualityi入堆,从而得到一个更小的 sumQ,此时有可能找到一个更优解 sumQ ⋅ r i \textit{sumQ}\cdot r_i sumQ⋅ri,更新答案。
时间复杂度:O(nlogn),其中 n 为 quality 的长度。排序的时间复杂度为 O(nlogn),后面和堆有关的时间复杂度为 O(nlogk),由于 k≤n,总的时间复杂度为 O(nlogn)。
空间复杂度:O(n)
public double mincostToHireWorkers(int[] quality, int[] wage, int k) {
int n=quality.length;
Integer[] idx=new Integer[n];
Arrays.setAll(idx,i->i);
Arrays.sort(idx,(a,b)->quality[b]*wage[a]-quality[a]*wage[b]);
double res=0;
double sumQ=0;
PriorityQueue<Integer> pq=new PriorityQueue<>((a,b)->b-a);
for(int i=0;i<k;i++){
sumQ+=quality[idx[i]];
pq.offer(quality[idx[i]]);
}
res=sumQ*((double)wage[idx[k-1]]/quality[idx[k-1]]);
for(int i=k;i<n;i++){
int q=quality[idx[i]];
if(q<pq.peek()){
sumQ-=pq.poll()-q;
pq.offer(q);
res=Math.min(res,sumQ*((double)wage[idx[i]]/q));
}
}
return res;
}
有任何问题,欢迎评论区交流,欢迎评论区提供其它解题思路(代码),也可以点个赞支持一下作者哈😄~