You are given two integers n
and k
and two integer arrays speed
and efficiency
both of length n
. There are n
engineers numbered from 1
to n
. speed[i]
and efficiency[i]
represent the speed and efficiency of the ith
engineer respectively.
Choose at most k
different engineers out of the n
engineers to form a team with the maximum performance.
The performance of a team is the sum of its engineers' speeds multiplied by the minimum efficiency among its engineers.
Return the maximum performance of this team. Since the answer can be a huge number, return it modulo 109 + 7
.
Example 1:
Input: n = 6, speed = [2,10,3,1,5,8], efficiency = [5,4,3,9,7,2], k = 2 Output: 60 Explanation: We have the maximum performance of the team by selecting engineer 2 (with speed=10 and efficiency=4) and engineer 5 (with speed=5 and efficiency=7). That is, performance = (10 + 5) * min(4, 7) = 60.
Example 2:
Input: n = 6, speed = [2,10,3,1,5,8], efficiency = [5,4,3,9,7,2], k = 3 Output: 68 Explanation: This is the same example as the first but k = 3. We can select engineer 1, engineer 2 and engineer 5 to get the maximum performance of the team. That is, performance = (2 + 10 + 5) * min(5, 4, 7) = 68.
Example 3:
Input: n = 6, speed = [2,10,3,1,5,8], efficiency = [5,4,3,9,7,2], k = 4 Output: 72
Constraints:
1 <= k <= n <= 105
speed.length == n
efficiency.length == n
1 <= speed[i] <= 105
1 <= efficiency[i] <= 108
This problem asks to find the maximum performance of a team formed by selecting at most k
engineers from a given set of n
engineers. The performance is calculated as the sum of the engineers' speeds multiplied by the minimum efficiency among the selected engineers.
The optimal solution uses a combination of sorting and a priority queue (heap). The core idea is to process engineers in decreasing order of efficiency. For each engineer, we add their speed to the current team's total speed. To ensure we don't exceed k
engineers, we maintain a min-heap of the speeds of the engineers currently in the team. If adding a new engineer exceeds k
engineers, we remove the engineer with the smallest speed from the heap to maintain the team size.
Algorithm:
Sort: Sort the engineers by efficiency in descending order. This ensures we consider the engineers with higher efficiency first, maximizing the potential performance. We can use a structure like a pair (speed, efficiency) to maintain the association between speed and efficiency for each engineer.
Initialize: Initialize a priority queue (min-heap) to store the speeds of the engineers currently in the team. Also, initialize variables tot
(total speed of the current team) and ans
(maximum performance found so far) to 0.
Iterate: Iterate through the sorted engineers. For each engineer:
tot
.ans
with the maximum of the current performance (tot * engineer's efficiency
) and the current ans
.k
, remove the smallest speed from the heap (using heappop
) and subtract it from tot
.Return: Return the maximum performance (ans
) modulo 10^9 + 7
.
Time Complexity Analysis:
Therefore, the overall time complexity is dominated by sorting, resulting in O(n log n).
Space Complexity Analysis:
The space complexity is determined by the priority queue, which stores at most k
elements. Therefore, the space complexity is O(k).
The provided code solutions are already quite efficient, but here are some slight improvements and clarifications:
Python:
import heapq
class Solution:
def maxPerformance(self, n: int, speed: List[int], efficiency: List[int], k: int) -> int:
engineers = sorted(zip(efficiency, speed), reverse=True) # Sort by efficiency (descending)
max_performance = 0
total_speed = 0
min_heap = [] # Use heapq for min-heap operations
mod = 10**9 + 7
for eff, spd in engineers:
total_speed += spd
heapq.heappush(min_heap, spd)
if len(min_heap) > k:
total_speed -= heapq.heappop(min_heap)
max_performance = max(max_performance, total_speed * eff)
return max_performance % mod
Java:
import java.util.*;
class Solution {
private static final int MOD = (int) 1e9 + 7;
public int maxPerformance(int n, int[] speed, int[] efficiency, int k) {
int[][] engineers = new int[n][2];
for (int i = 0; i < n; ++i) {
engineers[i] = new int[] {efficiency[i], speed[i]};
}
Arrays.sort(engineers, (a, b) -> b[0] - a[0]); // Sort by efficiency (descending)
long maxPerformance = 0;
long totalSpeed = 0;
PriorityQueue<Integer> minHeap = new PriorityQueue<>(); // Use PriorityQueue for min-heap
for (int[] eng : engineers) {
totalSpeed += eng[1];
minHeap.offer(eng[1]);
if (minHeap.size() > k) {
totalSpeed -= minHeap.poll();
}
maxPerformance = Math.max(maxPerformance, totalSpeed * eng[0]);
}
return (int) (maxPerformance % MOD);
}
}
C++:
#include <vector>
#include <algorithm>
#include <queue>
using namespace std;
class Solution {
public:
int maxPerformance(int n, vector<int>& speed, vector<int>& efficiency, int k) {
vector<pair<int, int>> engineers(n);
for (int i = 0; i < n; ++i) {
engineers[i] = {efficiency[i], speed[i]};
}
sort(engineers.rbegin(), engineers.rend()); // Sort by efficiency (descending)
long long maxPerformance = 0;
long long totalSpeed = 0;
priority_queue<int, vector<int>, greater<int>> minHeap; // Use priority_queue for min-heap
for (auto& eng : engineers) {
totalSpeed += eng.second;
minHeap.push(eng.second);
if (minHeap.size() > k) {
totalSpeed -= minHeap.top();
minHeap.pop();
}
maxPerformance = max(maxPerformance, totalSpeed * eng.first);
}
return (int) (maxPerformance % 1000000007);
}
};
Go: (This version is improved for clarity and efficiency using container/heap
)
package main
import (
"container/heap"
"sort"
)
func maxPerformance(n int, speed []int, efficiency []int, k int) int {
engineers := make([][]int, n)
for i := range speed {
engineers[i] = []int{efficiency[i], speed[i]}
}
sort.Slice(engineers, func(i, j int) bool { return engineers[i][0] > engineers[j][0] }) // Sort by efficiency
maxPerf := 0
totalSpeed := 0
minHeap := &IntHeap{}
heap.Init(minHeap)
mod := 1000000007
for _, eng := range engineers {
totalSpeed += eng[1]
heap.Push(minHeap, eng[1])
if minHeap.Len() > k {
totalSpeed -= heap.Pop(minHeap).(int)
}
maxPerf = max(maxPerf, totalSpeed*eng[0])
}
return maxPerf % mod
}
// An IntHeap is a min-heap of ints.
type IntHeap []int
func (h IntHeap) Len() int { return len(h) }
func (h IntHeap) Less(i, j int) bool { return h[i] < h[j] }
func (h IntHeap) Swap(i, j int) { h[i], h[j] = h[j], h[i] }
func (h *IntHeap) Push(x any) {
*h = append(*h, x.(int))
}
func (h *IntHeap) Pop() any {
old := *h
n := len(old)
x := old[n-1]
*h = old[0 : n-1]
return x
}
func max(a, b int) int {
if a > b {
return a
}
return b
}
These improved versions maintain the same time and space complexity as before but offer better readability and, in some cases, slightly optimized heap management. The use of standard library heap implementations ensures correctness and efficiency.