Skip to content

Commit bf49410

Browse files
committed
✨feat: add 857
1 parent 936a5ac commit bf49410

File tree

2 files changed

+114
-0
lines changed

2 files changed

+114
-0
lines changed

Index/堆.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
| [726. 原子的数量](https://leetcode-cn.com/problems/number-of-atoms/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/number-of-atoms/solution/gong-shui-san-xie-shi-yong-xiao-ji-qiao-l5ak4/) | 困难 | 🤩🤩🤩🤩 |
1818
| [786. 第 K 个最小的素数分数](https://leetcode-cn.com/problems/k-th-smallest-prime-fraction/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/k-th-smallest-prime-fraction/solution/gong-shui-san-xie-yi-ti-shuang-jie-you-x-8ymk/) | 中等 | 🤩🤩🤩 |
1919
| [846. 一手顺子](https://leetcode-cn.com/problems/hand-of-straights/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/hand-of-straights/solution/gong-shui-san-xie-shu-ju-jie-gou-mo-ni-t-4hxw/) | 中等 | 🤩🤩🤩 |
20+
| [857. 雇佣 K 名工人的最低成本](https://leetcode.cn/problems/minimum-cost-to-hire-k-workers/) | [LeetCode 题解链接](https://leetcode.cn/problems/minimum-cost-to-hire-k-workers/solution/by-ac_oier-u42f/) | 困难 | 🤩🤩🤩🤩🤩 |
2021
| [871. 最低加油次数](https://leetcode.cn/problems/minimum-number-of-refueling-stops/) | [LeetCode 题解链接](https://leetcode.cn/problems/minimum-number-of-refueling-stops/solution/by-ac_oier-q2mk/) | 困难 | 🤩🤩🤩🤩🤩 |
2122
| [954. 二倍数对数组](https://leetcode-cn.com/problems/array-of-doubled-pairs/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/array-of-doubled-pairs/solution/by-ac_oier-d1z7/) | 中等 | 🤩🤩🤩🤩 |
2223
| [987. 二叉树的垂序遍历](https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/vertical-order-traversal-of-a-binary-tree/solution/gong-shui-san-xie-yi-ti-shuang-jie-dfs-h-wfm3/) | 困难 | 🤩🤩🤩🤩🤩 |
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
### 题目描述
2+
3+
这是 LeetCode 上的 **[857. 雇佣 K 名工人的最低成本](https://leetcode.cn/problems/minimum-cost-to-hire-k-workers/solution/by-ac_oier-u42f/)** ,难度为 **困难**
4+
5+
Tag : 「枚举」、「优先队列(堆)」
6+
7+
8+
9+
`n` 名工人。 给定两个数组 `quality` 和 `wage` ,其中,`quality[i]` 表示第 `i` 名工人的工作质量,其最低期望工资为 `wage[i]` 。
10+
11+
现在我们想雇佣 `k` 名工人组成一个工资组。在雇佣 一组 `k` 名工人时,我们必须按照下述规则向他们支付工资:
12+
13+
* 对工资组中的每名工人,应当按其工作质量与同组其他工人的工作质量的比例来支付工资。
14+
* 工资组中的每名工人至少应当得到他们的最低期望工资。
15+
16+
给定整数 `k`,返回 组成满足上述条件的付费群体所需的最小金额 。在实际答案的 $10^{-5}$ 以内的答案将被接受。。
17+
18+
示例 1:
19+
```
20+
输入: quality = [10,20,5], wage = [70,50,30], k = 2
21+
22+
输出: 105.00000
23+
24+
解释: 我们向 0 号工人支付 70,向 2 号工人支付 35。
25+
```
26+
示例 2:
27+
```
28+
输入: quality = [3,1,10,10,1], wage = [4,8,2,2,7], k = 3
29+
30+
输出: 30.66667
31+
32+
解释: 我们向 0 号工人支付 4,向 2 号和 3 号分别支付 13.33333。
33+
```
34+
35+
提示:
36+
* $n = quality.length = wage.length$
37+
* $1 <= k <= n <= 10^4$
38+
* $1 <= quality[i], wage[i] <= 10^4$
39+
40+
---
41+
42+
### 枚举 + 优先队列(堆)
43+
44+
为了方便,我们令 `quality``qs``wage``ws`
45+
46+
从 $n$ 个工人中选 $k$ 个,使这 $k$ 个工人实际工资与其 $qs[i]$ 成比例,且实际工资不低于 $ws[i]$。
47+
48+
根据条件一,假设实际工资与能力值比值为 $t$,则所选工人的实际工资为 $qs[i] \times t$,再结合条件二可知 $qs[i] \times t >= ws[i]$,变形可得 $t >= \frac{ws[i]}{qs[i]}$。
49+
50+
那么在选定若干工人的情况下,为使得总支出最小,我们可以取 $t$ 为所有被选工人中的最大 $\frac{ws[i]}{qs[i]}$ 即可。
51+
52+
**因此最终的 $t$ 值必然是取自某个工人的实际比值 $\frac{ws[i]}{qs[i]}$,这引导我们可以通过「枚举」哪个工人的实际比值为实际 $t$ 值来做。**
53+
54+
假设我们已经预处理出所有工人的 $\frac{ws[i]}{qs[i]}$ 比值信息,并「从小到大」进行枚举(该过程可看做是以比值信息作为维度来枚举每个工人):假设当前处理到的比值为最终使用到的 $t$,我们能够选的工人必然是在该工人的左边(根据上述分析可知,被选的工人满足 $\frac{ws[i]}{qs[i]} <= t$ 条件)。
55+
56+
因此,我们可以使用二维数组 `ds` 记录下每个工人的 $\frac{ws[i]}{qs[i]}$ 比值信息:$ds[i][0] = \frac{ws[i]}{qs[i]}$,$ds[i][1] = i$。并对其进行排升序,枚举每个工人的实际比值,同时动态维护枚举过程中的最小 $k$ 个 $qs[i]$(使用「大根堆」处理),并使用单变量 `tot` 记录当前堆中的 $qs[i]$ 总和,$tot \times \frac{ws[i]}{qs[i]}$ 即是以当前比值作为实际 $t$ 值时的总成本,在所有总成本中取最小值即是答案。
57+
58+
Java 代码:
59+
```Java
60+
class Solution {
61+
public double mincostToHireWorkers(int[] qs, int[] ws, int k) {
62+
int n = qs.length;
63+
double[][] ds = new double[n][2];
64+
for (int i = 0; i < n; i++) {
65+
ds[i][0] = ws[i] * 1.0 / qs[i]; ds[i][1] = i * 1.0;
66+
}
67+
Arrays.sort(ds, (a,b)->Double.compare(a[0], b[0]));
68+
PriorityQueue<Integer> q = new PriorityQueue<>((a,b)->b-a);
69+
double ans = 1e18;
70+
for (int i = 0, tot = 0; i < n; i++) {
71+
int cur = qs[(int)ds[i][1]];
72+
tot += cur; q.add(cur);
73+
if (q.size() > k) tot -= q.poll();
74+
if (q.size() == k) ans = Math.min(ans, tot * ds[i][0]);
75+
}
76+
return ans;
77+
}
78+
}
79+
```
80+
TypeScript 代码:
81+
```TypeScript
82+
function mincostToHireWorkers(qs: number[], ws: number[], k: number): number {
83+
const n = qs.length
84+
const ds: number[][] = new Array<Array<number>>()
85+
for (let i = 0; i < n; i++) ds.push([ws[i] / qs[i], i])
86+
ds.sort((a,b)=>a[0]-b[0])
87+
const q = new MaxPriorityQueue()
88+
let ans = 1e18
89+
for (let i = 0, tot = 0; i < n; i++) {
90+
const cur = qs[ds[i][1]]
91+
tot += cur
92+
q.enqueue(cur)
93+
if (q.size() > k) tot -= q.dequeue().element
94+
if (q.size() == k) ans = Math.min(ans, tot * ds[i][0])
95+
}
96+
return ans
97+
};
98+
```
99+
* 时间复杂度:构造系数并排序复杂度为 $O(n\log{n})$;枚举并计算答案复杂度为 $O(n\log{k})$。整体复杂度为 $O(n\log{n})$
100+
* 空间复杂度:$O(n)$
101+
102+
---
103+
104+
### 最后
105+
106+
这是我们「刷穿 LeetCode」系列文章的第 `No.857` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
107+
108+
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
109+
110+
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode
111+
112+
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
113+

0 commit comments

Comments
 (0)