题目链接
雇佣 K 位工人的总代价
题目描述
注意点
- costs[i]是雇佣第 i 位工人的代价
- 每一轮雇佣后,剩余工人的下标可能会发生变化
- 一位工人只能被选择一次
- 如果剩余员工数目不足 candidates 人,那么下一轮雇佣他们中代价最小的一人
- 如果有多位代价相同且最小的工人,选择下标更小的一位工人
解答思路
- 因为每一轮需要从最前面 candidates 和最后面 candidates 人中选出代价最小的一位,且某位工人如果已经被雇佣,则需要从可选择的工人中剔除掉,所以考虑使用优先队列PriorityQueue存储每一轮前candidates和后candidates位工人,队顶存储的是代价最小的工人。又因为如果有多位代价相同且最小的工人,选择下标更小的一位工人,所以当PriorityQueue工人代价相同时,则在前面的工人更优先
- 一位工人只能被选择一次,所以在选择了队顶的工人后,需要将其从队列中弹出,再弹出工人位于前面还是后面选择从前面或后面再添加一位工人到队列中(没有多余的工人则不添加)
代码
class Solution {public long totalCost(int[] costs, int k, int candidates) {long res = 0L;int n = costs.length;// 堆顶的代价更小,如果代价相同则下标更小PriorityQueue<int[]> queue = new PriorityQueue<>((int[] x, int[] y) -> {if (x[0] == y[0]) {return x[1] - y[1];}return x[0] - y[0];});int left = 0, right = n - 1;for (int i = 0; i < candidates; i++) {// 保证元素不会重复加入if (left <= right) {// 左侧下标为0queue.offer(new int[]{costs[left], 0});left++;}if (left <= right) {// 右侧下标为1queue.offer(new int[]{costs[right], 1});right--;}}for (int i = 0; i < k; i++) {int[] arr = queue.poll();res += arr[0];// 员工已全部加入到队列中if (left > right) {continue;}if (arr[1] == 0) {queue.offer(new int[]{costs[left], 0});left++;} else {queue.offer(new int[]{costs[right], 1});right--;}}return res;}
}
关键点
- 优先队列存储前后candidates位工人,队列根据工人代价从小到大进行排序,如果代价相同,则根据其在前面candidates和后面candidates进行排序
- 需要注意越界问题,也就是剩余工人不足candidates的情况,防止某些工人未添加到优先队列的同时防止某些工人被添加多次到队列中