公司有编号为 1 到 n 的 n 个工程师,给你两个数组 speed 和 efficiency ,其中 speed[i] 和 efficiency[i] 分别代表第 i 位工程师的速度和效率。请你返回由最多 k 个工程师组成的 最大团队表现值 ,由于答案可能很大,请你返回结果对 10^9 + 7 取余后的结果。
团队表现值 的定义为:一个团队中「所有工程师速度的和」乘以他们「效率值中的最小值」。
示例 1:
输入:n = 6, speed = [2,10,3,1,5,8], efficiency = [5,4,3,9,7,2], k = 2
输出:60
解释:
我们选择工程师 2(speed=10 且 efficiency=4)和工程师 5(speed=5 且 efficiency=7)。他们的团队表现值为 performance = (10 + 5) * min(4, 7) = 60 。
示例 2:
输入:n = 6, speed = [2,10,3,1,5,8], efficiency = [5,4,3,9,7,2], k = 3
输出:68
解释:
此示例与第一个示例相同,除了 k = 3 。我们可以选择工程师 1 ,工程师 2 和工程师 5 得到最大的团队表现值。表现值为 performance = (2 + 10 + 5) * min(5, 4, 7) = 68 。
示例 3:
输入:n = 6, speed = [2,10,3,1,5,8], efficiency = [5,4,3,9,7,2], k = 4
输出:72
提示:
1 <= n <= 10^5
speed.length == n
efficiency.length == n
1 <= speed[i] <= 10^5
1 <= efficiency[i] <= 10^8
1 <= k <= n
解答:
先说一下这道题吧,这道题的思路是:按照效率把所有的工程师从高到低进行排序,这样我们数到哪个工程师,这个工程师的效率就是计算效率。
怎么获得所有的速度和呢?我们把所有的速度放到一个集合里面,但是这个集合得是有序的,因为加入太多的值之后,我们要移除最小的值,这样才能保证留下的速度和最大。
我们依次计算所有可能性的结果,那最大的结果就找到了。
对工程师按照效率排序不难,难的就是保证速度集合有序。
自以为聪明的我,想到了链表,因为如果使用数组,每次插入一个值,整个数组移动太大。
但是链表要找到插在哪,是不是有很困难,我又加入TreeMap,找到我插在谁的后面。
这样,当链表过长时,把首节点移除。保证剩下的速度和最大。
代码1)就是这个思路。
执行完毕,我去,110ms,仅比不到10%的强。看了一下比较快的代码。PriorityQueue,我好像有点印象,真想抽一下自己。
把代码进行优化,看代码2)
不过我还是很好奇,它是怎么做到每次取出来的都是最小呢?我看了源码,说实话,有点云里雾里,但是我被一个方法的单词吸引了,heapify,查了一下,是数组建堆,我立马就醒悟了。对啊,我说这<<<的在干嘛,这不就是和上一个父节点比较嘛
看图就明白了。
0
/ \
1 2
/ \ / \
3 4 5 6
/ \
7 8
我数组建成堆之后,第7位的父节点是3,第2位的子节点是5和6,这样立即明白(k-1)>>>1是在干嘛了,不就是找父节点吗。
我们只要保证,子节点永远不小于父节点,这样根节点就永远最小了
那我自己建堆行不行?我的Queue比较简单,目标对象就是int类型的,数组长度也固定,不需要判断扩容,甚至,我都可以不用new Queue操作。
代码见代码3)
后面我会写一篇PriorityQueue的源码阅读,flag先立在这里。
最近学习斐波那契堆,感觉可以在这用
算法导论第19章-斐波那契堆的学习笔记(以及LeetCode1383的斐波那契堆的做法)
代码1)
long allNum = 0;
Node head;
TreeMap<Integer, Node> nodeTreeMap = new TreeMap<>();
long NN = 1000000;
public int maxPerformance(int n, int[] speed, int[] efficiency, int k) {
if (k == 0) {
return 0;
}
Long[] effSpee = new Long[n];
for (int i = 0; i < n; i++) {
effSpee[i] = efficiency[i] * NN + speed[i];
}
Arrays.sort(effSpee, new Comparator<Long>() {
@Override
public int compare(Long o1, Long o2) {
return o2.compareTo(o1);
}
});
head = new Node((int) (effSpee[0] % NN));
nodeTreeMap.put(head.value, head);
allNum += head.value;
long ans = (effSpee[0] / NN) * allNum;
int sta = 1;
while (sta < k) {
long v = (effSpee[sta] / NN);
int nspeed = (int) (effSpee[sta] % NN);
allNum += nspeed;
Node nNode = new Node(nspeed);
if (nspeed <= head.value) {
nNode.next = head;
head = nNode;
} else {
Node lefNode = nodeTreeMap.floorEntry(nspeed).getValue();
nNode.next = lefNode.next;
lefNode.next = nNode;
}
nodeTreeMap.put(nspeed, nNode);
sta++;
ans = Math.max(ans, v * allNum);
}
for (int i = k; i < n; i++) {
long v = (effSpee[i] / NN);
if (v == 0) {
return (int) (ans % 1000000007);
}
int nspeed = (int) (effSpee[i] % NN);
if (nspeed <= head.value) {
continue;
}
allNum += nspeed;
allNum -= head.value;
Node nNode = new Node(nspeed);
Node lefNode = nodeTreeMap.floorEntry(nspeed).getValue();
nNode.next = lefNode.next;
lefNode.next = nNode;
nodeTreeMap.put(nspeed, nNode);
head = head.next;
ans = Math.max(ans, v * allNum);
}
return (int) (ans % 1000000007);
}
class Node {
int value;
Node next;
public Node(int speed) {
value = speed;
}
}
代码2)
long NN = 1000000;
public int maxPerformance(int n, int[] speed, int[] efficiency, int k) {
if (k == 0) {
return 0;
}
Long[] effSpee = new Long[n];
for (int i = 0; i < n; i++) {
effSpee[i] = efficiency[i] * NN + speed[i];
}
Arrays.sort(effSpee, new Comparator<Long>() {
@Override
public int compare(Long o1, Long o2) {
return o2.compareTo(o1);
}
});
PriorityQueue<Integer> integerPriorityQueue = new PriorityQueue<>(k);
long allNum = 0;
long ans = 0;
for (int i = 0; i < n; i++) {
int nspeed = (int) (effSpee[i] % NN);
long v = (effSpee[i] / NN);
allNum += nspeed;
integerPriorityQueue.add(nspeed);
if (i >= k) {
allNum -= integerPriorityQueue.poll();
}
ans = Math.max(ans, v * allNum);
}
return (int) (ans % 1000000007);
}
代码3)
long NN = 1000000;
public int maxPerformance(int n, int[] speed, int[] efficiency, int k) {
if (k == 0) {
return 0;
}
Long[] effSpee = new Long[n];
for (int i = 0; i < n; i++) {
effSpee[i] = efficiency[i] * NN + speed[i];
}
Arrays.sort(effSpee, new Comparator<Long>() {
@Override
public int compare(Long o1, Long o2) {
return o2.compareTo(o1);
}
});
len = k;
values = new int[len];
add((int) (effSpee[0] % NN));
long allNum = (int) (effSpee[0] % NN);
long ans = (effSpee[0] / NN) * allNum;
for (int i = 1; i < n; i++) {
int nspeed = (int) (effSpee[i] % NN);
long v = (effSpee[i] / NN);
if (i >= k) {
if (nspeed <= peek()) {
continue;
} else {
allNum -= poll();
}
}
allNum += nspeed;
add(nspeed);
ans = Math.max(ans, v * allNum);
}
return (int) (ans % 1000000007);
}
int size = 0;
int len = 16;
int[] values;
public void add(int v) {
values[size] = v;
if (size > 0) {
checkAdd(size, v);
}
size++;
}
private void checkAdd(int k, int v) {
while (k > 0) {
int p = (k - 1) >>> 1;
if (values[p] < v) {
break;
}
values[k] = values[p];
k = p;
}
values[k] = v;
}
public int poll() {
int ans = values[0];
values[0] = values[--size];
checkRemove(0, values[0]);
return ans;
}
private void checkRemove(int k, int v) {
int half = size >>> 1;
while (k < half) {
int left = 2 * k + 1;
int right = 2 * k + 2;
if (v <= values[left] && v <= values[right]) {
break;
}
if (values[left] < values[right]) {
values[k] = values[left];
k = left;
} else {
values[k] = values[right];
k = right;
}
}
values[k] = v;
}
public int peek() {
return values[0];
}