Off-by-one on range boundaries
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Break down a hard problem into reliable checkpoints, edge-case handling, and complexity trade-offs.
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 <= 105speed.length == nefficiency.length == n1 <= speed[i] <= 1051 <= efficiency[i] <= 108Problem summary: 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.
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Array · Greedy
6 [2,10,3,1,5,8] [5,4,3,9,7,2] 2
6 [2,10,3,1,5,8] [5,4,3,9,7,2] 3
6 [2,10,3,1,5,8] [5,4,3,9,7,2] 4
maximum-fruits-harvested-after-at-most-k-steps)Source-backed implementations are provided below for direct study and interview prep.
// Accepted solution for LeetCode #1383: Maximum Performance of a Team
class Solution {
private static final int MOD = (int) 1e9 + 7;
public int maxPerformance(int n, int[] speed, int[] efficiency, int k) {
int[][] t = new int[n][2];
for (int i = 0; i < n; ++i) {
t[i] = new int[] {speed[i], efficiency[i]};
}
Arrays.sort(t, (a, b) -> b[1] - a[1]);
PriorityQueue<Integer> q = new PriorityQueue<>();
long tot = 0;
long ans = 0;
for (var x : t) {
int s = x[0], e = x[1];
tot += s;
ans = Math.max(ans, tot * e);
q.offer(s);
if (q.size() == k) {
tot -= q.poll();
}
}
return (int) (ans % MOD);
}
}
// Accepted solution for LeetCode #1383: Maximum Performance of a Team
func maxPerformance(n int, speed []int, efficiency []int, k int) int {
t := make([][]int, n)
for i, s := range speed {
t[i] = []int{s, efficiency[i]}
}
sort.Slice(t, func(i, j int) bool { return t[i][1] > t[j][1] })
var mod int = 1e9 + 7
ans, tot := 0, 0
pq := hp{}
for _, x := range t {
s, e := x[0], x[1]
tot += s
ans = max(ans, tot*e)
heap.Push(&pq, s)
if pq.Len() == k {
tot -= heap.Pop(&pq).(int)
}
}
return ans % mod
}
type hp struct{ sort.IntSlice }
func (h *hp) Push(v any) { h.IntSlice = append(h.IntSlice, v.(int)) }
func (h *hp) Pop() any {
a := h.IntSlice
v := a[len(a)-1]
h.IntSlice = a[:len(a)-1]
return v
}
func (h *hp) Less(i, j int) bool { return h.IntSlice[i] < h.IntSlice[j] }
# Accepted solution for LeetCode #1383: Maximum Performance of a Team
class Solution:
def maxPerformance(
self, n: int, speed: List[int], efficiency: List[int], k: int
) -> int:
t = sorted(zip(speed, efficiency), key=lambda x: -x[1])
ans = tot = 0
mod = 10**9 + 7
h = []
for s, e in t:
tot += s
ans = max(ans, tot * e)
heappush(h, s)
if len(h) == k:
tot -= heappop(h)
return ans % mod
// Accepted solution for LeetCode #1383: Maximum Performance of a Team
struct Solution;
use std::cmp::Reverse;
use std::collections::BinaryHeap;
const MOD: i64 = 1_000_000_007;
impl Solution {
fn max_performance(n: i32, speed: Vec<i32>, efficiency: Vec<i32>, k: i32) -> i32 {
let n = n as usize;
let k = k as usize;
let mut max_efficiency: BinaryHeap<(i32, i32)> = BinaryHeap::new();
for i in 0..n {
max_efficiency.push((efficiency[i], speed[i]));
}
let mut min_speed: BinaryHeap<Reverse<i32>> = BinaryHeap::new();
let mut sum_speed = 0;
let mut res = 0;
while let Some((e, s)) = max_efficiency.pop() {
sum_speed += s as i64;
min_speed.push(Reverse(s));
if min_speed.len() > k {
sum_speed -= min_speed.pop().unwrap().0 as i64;
}
res = res.max(sum_speed as i64 * e as i64);
}
(res % MOD) as i32
}
}
#[test]
fn test() {
let n = 6;
let speed = vec![2, 10, 3, 1, 5, 8];
let efficiency = vec![5, 4, 3, 9, 7, 2];
let k = 2;
let res = 60;
assert_eq!(Solution::max_performance(n, speed, efficiency, k), res);
let n = 6;
let speed = vec![2, 10, 3, 1, 5, 8];
let efficiency = vec![5, 4, 3, 9, 7, 2];
let k = 3;
let res = 68;
assert_eq!(Solution::max_performance(n, speed, efficiency, k), res);
let n = 6;
let speed = vec![2, 10, 3, 1, 5, 8];
let efficiency = vec![5, 4, 3, 9, 7, 2];
let k = 4;
let res = 72;
assert_eq!(Solution::max_performance(n, speed, efficiency, k), res);
}
// Accepted solution for LeetCode #1383: Maximum Performance of a Team
// Auto-generated TypeScript example from java.
function exampleSolution(): void {
}
// Reference (java):
// // Accepted solution for LeetCode #1383: Maximum Performance of a Team
// class Solution {
// private static final int MOD = (int) 1e9 + 7;
//
// public int maxPerformance(int n, int[] speed, int[] efficiency, int k) {
// int[][] t = new int[n][2];
// for (int i = 0; i < n; ++i) {
// t[i] = new int[] {speed[i], efficiency[i]};
// }
// Arrays.sort(t, (a, b) -> b[1] - a[1]);
// PriorityQueue<Integer> q = new PriorityQueue<>();
// long tot = 0;
// long ans = 0;
// for (var x : t) {
// int s = x[0], e = x[1];
// tot += s;
// ans = Math.max(ans, tot * e);
// q.offer(s);
// if (q.size() == k) {
// tot -= q.poll();
// }
// }
// return (int) (ans % MOD);
// }
// }
Use this to step through a reusable interview workflow for this problem.
Try every possible combination of choices. With n items each having two states (include/exclude), the search space is 2ⁿ. Evaluating each combination takes O(n), giving O(n × 2ⁿ). The recursion stack or subset storage uses O(n) space.
Greedy algorithms typically sort the input (O(n log n)) then make a single pass (O(n)). The sort dominates. If the input is already sorted or the greedy choice can be computed without sorting, time drops to O(n). Proving greedy correctness (exchange argument) is harder than the implementation.
Review these before coding to avoid predictable interview regressions.
Wrong move: Loop endpoints miss first/last candidate.
Usually fails on: Fails on minimal arrays and exact-boundary answers.
Fix: Re-derive loops from inclusive/exclusive ranges before coding.
Wrong move: Locally optimal choices may fail globally.
Usually fails on: Counterexamples appear on crafted input orderings.
Fix: Verify with exchange argument or monotonic objective before committing.