公司有編號爲 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];
}