1626. Best Team With No Conflicts
Problem Description
You need to select players for a basketball team to maximize the total score, but there's a special constraint about player conflicts.
The Goal: Choose a subset of players whose scores sum to the highest possible value.
The Conflict Rule: A conflict occurs when a younger player has a strictly higher score than an older player on the same team. This means:
- If player A is younger than player B, and player A has a higher score than player B, they cannot both be on the team
- Players of the same age never create conflicts with each other
Input:
scores
: An array wherescores[i]
is the score of the i-th playerages
: An array whereages[i]
is the age of the i-th player
Output: The maximum possible sum of scores for a valid team (a team with no conflicts)
Example to understand conflicts:
- Player A: age 20, score 100
- Player B: age 25, score 90
- These two CAN be on the same team (older player has lower score - no conflict)
But if:
- Player A: age 20, score 100
- Player B: age 25, score 90
- Player C: age 18, score 95
- Player C cannot be with Player A (C is younger but has lower score than A - this creates a conflict)
The challenge is finding the optimal combination of players that respects the conflict rule while maximizing the total score.
Intuition
The key insight is recognizing that this is a dynamic programming problem similar to finding the longest increasing subsequence, but with a twist involving two parameters (age and score).
Let's think about when we can add players without conflicts. If we sort players by score first, then for any player we're considering, we can only add them to a team if their age is greater than or equal to all players with lower or equal scores already on the team. This suggests we need some ordering to process players systematically.
By sorting players by (score, age)
, we create a useful property: when we process players from left to right, we know that any player to the left has a score that's less than or equal to the current player's score. Now the conflict constraint simplifies - we can add the current player to any previous team as long as their age is greater than or equal to the ages of all players in that team.
Since we're processing in score order, and we only need to check age compatibility, this becomes similar to finding the maximum sum subsequence where ages form a non-decreasing sequence.
For each player at position i
, we ask: "What's the best team score I can achieve if this player is included?" To answer this, we look at all previous players j
where j < i
. If the current player's age is >= arr[j]
's age, there's no conflict (since scores are already in order). We can extend the best team ending at position j
by adding the current player.
The formula becomes: f[i] = max(f[j] for all valid j) + current_score
This dynamic programming approach ensures we consider all valid combinations while building up to the optimal solution. The final answer is the maximum value in our DP array, representing the best possible team score.
Learn more about Dynamic Programming and Sorting patterns.
Solution Approach
The implementation follows a dynamic programming approach with careful preprocessing:
Step 1: Sort and Prepare Data
arr = sorted(zip(scores, ages))
We create pairs of (score, age)
and sort them. Python sorts tuples lexicographically, so this sorts primarily by score, and secondarily by age when scores are equal. This ordering is crucial - it ensures that when we process player i
, all players before it have scores ≤
player i
's score.
Step 2: Initialize DP Array
f = [0] * n
Create a DP array where f[i]
represents the maximum team score achievable when player i
is the last player added to the team (sorted order).
Step 3: Fill DP Table
for i, (score, age) in enumerate(arr):
for j in range(i):
if age >= arr[j][1]:
f[i] = max(f[i], f[j])
f[i] += score
For each player i
:
- We iterate through all previous players
j
(wherej < i
) - Check if adding player
i
after playerj
creates no conflict:age >= arr[j][1]
- Since scores are sorted, we know
score_i ≥ score_j
- If
age_i ≥ age_j
, then no conflict exists
- Since scores are sorted, we know
- If compatible, we update
f[i]
to be the maximum of its current value andf[j]
- After checking all possible previous players, add the current player's score:
f[i] += score
Step 4: Return Maximum
return max(f)
The answer is the maximum value in the DP array, as it represents the best possible team score across all valid ending positions.
Time Complexity: O(n²)
due to the nested loops
Space Complexity: O(n)
for the DP array and sorted pairs
The elegance of this solution lies in how sorting transforms a complex two-parameter conflict check into a simple age comparison, making the DP transition straightforward.
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example to illustrate the solution approach.
Input:
scores = [4, 5, 6, 5]
ages = [2, 1, 2, 1]
Step 1: Sort by (score, age) After creating pairs and sorting:
arr = [(4, 2), (5, 1), (5, 1), (6, 2)]
Players are now ordered by score first, then age.
Step 2: Initialize DP array
f = [0, 0, 0, 0]
Step 3: Fill DP table
Process player 0: (score=4, age=2)
- No previous players to check
f[0] = 0 + 4 = 4
- DP state:
f = [4, 0, 0, 0]
Process player 1: (score=5, age=1)
- Check player 0: age=1 vs arr[0][1]=2
- 1 < 2, so incompatible (younger player with higher score creates conflict)
- No valid previous players
f[1] = 0 + 5 = 5
- DP state:
f = [4, 5, 0, 0]
Process player 2: (score=5, age=1)
- Check player 0: age=1 vs arr[0][1]=2
- 1 < 2, incompatible
- Check player 1: age=1 vs arr[1][1]=1
- 1 >= 1, compatible! Update:
f[2] = max(0, f[1]) = 5
- 1 >= 1, compatible! Update:
f[2] = 5 + 5 = 10
- DP state:
f = [4, 5, 10, 0]
Process player 3: (score=6, age=2)
- Check player 0: age=2 vs arr[0][1]=2
- 2 >= 2, compatible! Update:
f[3] = max(0, f[0]) = 4
- 2 >= 2, compatible! Update:
- Check player 1: age=2 vs arr[1][1]=1
- 2 >= 1, compatible! Update:
f[3] = max(4, f[1]) = 5
- 2 >= 1, compatible! Update:
- Check player 2: age=2 vs arr[2][1]=1
- 2 >= 1, compatible! Update:
f[3] = max(5, f[2]) = 10
- 2 >= 1, compatible! Update:
f[3] = 10 + 6 = 16
- DP state:
f = [4, 5, 10, 16]
Step 4: Return maximum
max(f) = 16
The optimal team consists of players with (score=5, age=1), (score=5, age=1), and (score=6, age=2), giving a total score of 16. This team has no conflicts because when sorted by score, the ages form a non-decreasing sequence: [1, 1, 2].
Solution Implementation
1class Solution:
2 def bestTeamScore(self, scores: List[int], ages: List[int]) -> int:
3 # Combine scores and ages, then sort by score (and implicitly by age if scores are equal)
4 players = sorted(zip(scores, ages))
5 n = len(players)
6
7 # dp[i] represents the maximum team score ending with player i
8 dp = [0] * n
9
10 # Process each player as a potential team member
11 for i, (current_score, current_age) in enumerate(players):
12 # Check all previous players (with lower or equal scores)
13 for j in range(i):
14 previous_score, previous_age = players[j]
15 # No conflict if current player is older or same age as previous player
16 # Since players are sorted by score, we know current_score >= previous_score
17 if current_age >= previous_age:
18 dp[i] = max(dp[i], dp[j])
19
20 # Add current player's score to the best team ending with them
21 dp[i] += current_score
22
23 # Return the maximum team score among all possible teams
24 return max(dp)
25
1class Solution {
2 public int bestTeamScore(int[] scores, int[] ages) {
3 int n = ages.length;
4
5 // Create a 2D array to store [score, age] pairs for each player
6 int[][] players = new int[n][2];
7 for (int i = 0; i < n; i++) {
8 players[i] = new int[] {scores[i], ages[i]};
9 }
10
11 // Sort players by score (ascending), if scores are equal then by age (ascending)
12 // This ensures no conflicts when building teams with increasing scores
13 Arrays.sort(players, (a, b) -> {
14 if (a[0] == b[0]) {
15 return a[1] - b[1]; // Sort by age if scores are equal
16 }
17 return a[0] - b[0]; // Sort by score primarily
18 });
19
20 // Dynamic programming array where dp[i] represents the maximum team score
21 // ending with player i
22 int[] dp = new int[n];
23 int maxTeamScore = 0;
24
25 // Build up the DP solution
26 for (int i = 0; i < n; i++) {
27 // Check all previous players that can be on the same team
28 for (int j = 0; j < i; j++) {
29 // A player j can be on the same team with player i if:
30 // player i's age >= player j's age (since scores are already sorted)
31 // This avoids conflicts where younger player has higher score
32 if (players[i][1] >= players[j][1]) {
33 dp[i] = Math.max(dp[i], dp[j]);
34 }
35 }
36
37 // Add current player's score to the team
38 dp[i] += players[i][0];
39
40 // Update the maximum team score found so far
41 maxTeamScore = Math.max(maxTeamScore, dp[i]);
42 }
43
44 return maxTeamScore;
45 }
46}
47
1class Solution {
2public:
3 int bestTeamScore(vector<int>& scores, vector<int>& ages) {
4 int n = ages.size();
5
6 // Create pairs of (score, age) for each player
7 vector<pair<int, int>> players(n);
8 for (int i = 0; i < n; ++i) {
9 players[i] = {scores[i], ages[i]};
10 }
11
12 // Sort players by score (ascending), and by age if scores are equal
13 sort(players.begin(), players.end());
14
15 // dp[i] represents the maximum team score ending with player i
16 vector<int> dp(n);
17
18 // Calculate maximum score for each player as the last player in team
19 for (int i = 0; i < n; ++i) {
20 // Check all previous players that can be included without conflict
21 for (int j = 0; j < i; ++j) {
22 // No conflict if current player's age >= previous player's age
23 // (since scores are already sorted, no score conflict exists)
24 if (players[i].second >= players[j].second) {
25 dp[i] = max(dp[i], dp[j]);
26 }
27 }
28 // Add current player's score to the maximum compatible team score
29 dp[i] += players[i].first;
30 }
31
32 // Return the maximum score among all possible teams
33 return *max_element(dp.begin(), dp.end());
34 }
35};
36
1/**
2 * Finds the maximum score of the best team with no conflicts.
3 * A conflict exists when a younger player has a higher score than an older player.
4 *
5 * @param scores - Array of player scores
6 * @param ages - Array of player ages (corresponding to scores)
7 * @returns Maximum possible team score without conflicts
8 */
9function bestTeamScore(scores: number[], ages: number[]): number {
10 // Create array of [age, score] pairs for each player
11 const players: [number, number][] = ages.map((age, index) => [age, scores[index]]);
12
13 // Sort players by age (ascending), then by score (ascending) if ages are equal
14 // This ensures no conflicts when building teams
15 players.sort((playerA, playerB) => {
16 if (playerA[0] === playerB[0]) {
17 return playerA[1] - playerB[1]; // Same age: sort by score
18 }
19 return playerA[0] - playerB[0]; // Different age: sort by age
20 });
21
22 const playerCount: number = players.length;
23
24 // Dynamic programming array: dp[i] represents the maximum score
25 // achievable using players from index 0 to i, with player i included
26 const dp: number[] = new Array(playerCount).fill(0);
27
28 // Build up the DP solution
29 for (let currentPlayer = 0; currentPlayer < playerCount; currentPlayer++) {
30 // Check all previous players to find compatible teams
31 for (let previousPlayer = 0; previousPlayer < currentPlayer; previousPlayer++) {
32 // If current player's score >= previous player's score,
33 // they can be on the same team (no conflict due to age sorting)
34 if (players[currentPlayer][1] >= players[previousPlayer][1]) {
35 dp[currentPlayer] = Math.max(dp[currentPlayer], dp[previousPlayer]);
36 }
37 }
38 // Add current player's score to the best team score found
39 dp[currentPlayer] += players[currentPlayer][1];
40 }
41
42 // Return the maximum score among all possible teams
43 return Math.max(...dp);
44}
45
Time and Space Complexity
Time Complexity: O(n^2)
The algorithm first sorts the array of (score, age)
pairs, which takes O(n log n)
time. Then it uses dynamic programming with a nested loop structure:
- The outer loop iterates through all
n
elements - For each element
i
, the inner loop iterates through all previous elements from0
toi-1
- Inside the inner loop, operations are
O(1)
(comparison and max calculation)
Therefore, the nested loops contribute O(n^2)
time complexity. Since O(n^2)
dominates O(n log n)
, the overall time complexity is O(n^2)
.
Space Complexity: O(n)
The algorithm uses:
arr
: A sorted list of tuples containingn
elements, requiringO(n)
spacef
: A DP array of sizen
to store the maximum scores, requiringO(n)
space- A few constant variables (
i
,j
,score
,age
,n
)
The sorting operation may use O(n)
additional space depending on the implementation. Overall, the space complexity is O(n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Incorrect Sorting Strategy
The Problem: Many developers initially sort by age instead of score, thinking they need to process players from youngest to oldest or vice versa. This leads to incorrect DP transitions because you can't efficiently determine which previous players are compatible.
Why it happens: The conflict rule mentions "younger player with higher score," so it's intuitive to think age should be the primary sorting key.
Example of incorrect approach:
# WRONG: Sorting by age first
players = sorted(zip(ages, scores)) # This won't work!
The Solution: Sort by score (not age) as the primary key. When sorted by score, checking compatibility becomes simple: you only need to verify that the current player's age is ≥ the previous player's age, since the score condition is automatically satisfied by the sorting order.
Pitfall 2: Misunderstanding the Conflict Rule
The Problem: Interpreting the conflict rule incorrectly, such as thinking that any age difference with a score difference creates a conflict, or missing that players of the same age never conflict.
Common misinterpretations:
- Thinking older players with higher scores create conflicts with younger players (they don't)
- Forgetting that equal ages mean no conflict regardless of scores
- Assuming you need to check both age AND score in the DP transition (you don't after sorting)
The Solution: Remember the conflict only occurs in one specific direction: younger player with strictly higher score than an older player. After sorting by score, you only need to check if current_age >= previous_age
.
Pitfall 3: Forgetting to Initialize DP with Current Player's Score
The Problem: Some implementations forget that a player can form a team by themselves, leading to incorrect base cases.
Example of incorrect code:
# WRONG: Not considering single-player teams
for i in range(n):
for j in range(i):
if current_age >= previous_age:
dp[i] = max(dp[i], dp[j] + current_score)
# This misses the case where player i forms a team alone
The Solution: Always add the current player's score after checking all previous players. This ensures that even if no previous players are compatible, the current player can still form a valid team by themselves.
Pitfall 4: Using Wrong Comparison in DP Transition
The Problem: After sorting by score, using the wrong age comparison in the transition check.
Example of incorrect check:
# WRONG: Reversed age comparison
if current_age < previous_age: # This is backwards!
dp[i] = max(dp[i], dp[j])
The Solution: After sorting by score in ascending order, use current_age >= previous_age
. This ensures no conflict since:
- Current score ≥ previous score (guaranteed by sorting)
- Current age ≥ previous age (checked explicitly)
- Therefore, we don't have a "younger with higher score" situation
Which of the following uses divide and conquer strategy?
Recommended Readings
What is Dynamic Programming Prerequisite DFS problems dfs_intro Backtracking problems backtracking Memoization problems memoization_intro Pruning problems backtracking_pruning Dynamic programming is an algorithmic optimization technique that breaks down a complicated problem into smaller overlapping sub problems in a recursive manner and uses solutions to the sub problems to construct a solution
Sorting Summary Comparisons We presented quite a few sorting algorithms and it is essential to know the advantages and disadvantages of each one The basic algorithms are easy to visualize and easy to learn for beginner programmers because of their simplicity As such they will suffice if you don't know any advanced
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Want a Structured Path to Master System Design Too? Don’t Miss This!