questions B (backspace - burst-balloons)
This commit is contained in:
186
backend/data/questions/best-team-with-no-conflicts.yaml
Normal file
186
backend/data/questions/best-team-with-no-conflicts.yaml
Normal file
@@ -0,0 +1,186 @@
|
||||
title: Best Team With No Conflicts
|
||||
slug: best-team-with-no-conflicts
|
||||
difficulty: medium
|
||||
leetcode_id: 1626
|
||||
leetcode_url: https://leetcode.com/problems/best-team-with-no-conflicts/
|
||||
categories:
|
||||
- arrays
|
||||
- dynamic-programming
|
||||
- sorting
|
||||
patterns:
|
||||
- dynamic-programming
|
||||
|
||||
description: |
|
||||
You are the manager of a basketball team. For the upcoming tournament, you want to choose the team with the highest overall score. The score of the team is the **sum** of scores of all the players in the team.
|
||||
|
||||
However, the basketball team is not allowed to have **conflicts**. A **conflict** exists if a younger player has a **strictly higher** score than an older player. A conflict does **not** occur between players of the same age.
|
||||
|
||||
Given two lists, `scores` and `ages`, where each `scores[i]` and `ages[i]` represents the score and age of the i<sup>th</sup> player, respectively, return *the highest overall score of all possible basketball teams*.
|
||||
|
||||
constraints: |
|
||||
- `1 <= scores.length, ages.length <= 1000`
|
||||
- `scores.length == ages.length`
|
||||
- `1 <= scores[i] <= 10^6`
|
||||
- `1 <= ages[i] <= 1000`
|
||||
|
||||
examples:
|
||||
- input: "scores = [1,3,5,10,15], ages = [1,2,3,4,5]"
|
||||
output: "34"
|
||||
explanation: "You can choose all the players. Since ages are strictly increasing and scores are also strictly increasing, no conflicts exist."
|
||||
- input: "scores = [4,5,6,5], ages = [2,1,2,1]"
|
||||
output: "16"
|
||||
explanation: "It is best to choose the last 3 players (scores 5, 6, 5 with ages 1, 2, 1). Notice that you are allowed to choose multiple people of the same age."
|
||||
- input: "scores = [1,2,3,5], ages = [8,9,10,1]"
|
||||
output: "6"
|
||||
explanation: "It is best to choose the first 3 players (scores 1, 2, 3). The player with score 5 and age 1 cannot be included because they are younger but have a higher score than the others."
|
||||
|
||||
explanation:
|
||||
intuition: |
|
||||
Imagine you're sorting players into a roster where **seniority must be respected** — older players shouldn't be outscored by younger ones.
|
||||
|
||||
The key insight is that this is a **variant of the Longest Increasing Subsequence (LIS) problem**, but instead of finding the longest subsequence, we want the one with the **maximum sum**.
|
||||
|
||||
Think of it this way: if we sort all players by age (and by score as a tiebreaker for same-age players), then we need to find a subsequence where scores are **non-decreasing**. Why? Because after sorting by age, any player we pick later is at least as old. If their score is also at least as high, there's no conflict.
|
||||
|
||||
This transformation is powerful — it converts a 2D constraint (age AND score) into a 1D problem (just scores, after sorting).
|
||||
|
||||
approach: |
|
||||
We use **Dynamic Programming** after sorting the players:
|
||||
|
||||
**Step 1: Combine and sort players**
|
||||
|
||||
- Create pairs of `(age, score)` for each player
|
||||
- Sort by age first, then by score (both ascending)
|
||||
- This ensures when we process player `j` after player `i`, player `j` is at least as old
|
||||
|
||||
|
||||
|
||||
**Step 2: Define the DP state**
|
||||
|
||||
- `dp[i]`: Maximum total score of a valid team ending with the i<sup>th</sup> player (after sorting)
|
||||
- Base case: Each player alone forms a valid team, so `dp[i] = score[i]` initially
|
||||
|
||||
|
||||
|
||||
**Step 3: Fill the DP table**
|
||||
|
||||
- For each player `i`, look at all previous players `j` where `j < i`
|
||||
- If `score[j] <= score[i]`, player `j` can be on the same team as player `i` (no conflict)
|
||||
- Update: `dp[i] = max(dp[i], dp[j] + score[i])`
|
||||
|
||||
|
||||
|
||||
**Step 4: Return the answer**
|
||||
|
||||
- The answer is `max(dp)` — the best team might end at any player
|
||||
|
||||
|
||||
|
||||
The sorting step is crucial: it ensures that when comparing players `j` and `i` (with `j < i`), player `j` is no older than player `i`. Combined with checking `score[j] <= score[i]`, we guarantee no conflicts.
|
||||
|
||||
common_pitfalls:
|
||||
- title: Forgetting to Sort by Score as Tiebreaker
|
||||
description: |
|
||||
When two players have the same age, their relative order matters. If you only sort by age, you might miss valid combinations.
|
||||
|
||||
For example, with ages `[2, 2]` and scores `[5, 3]`, sorting only by age could give either order. If you process the player with score 5 first and then score 3, you'd incorrectly think you can't include both (since 3 < 5 but same age means no conflict!).
|
||||
|
||||
By sorting by score as a secondary key, players of the same age are ordered by score, ensuring the DP comparison works correctly.
|
||||
wrong_approach: "Sort by age only"
|
||||
correct_approach: "Sort by (age, score) to handle same-age players correctly"
|
||||
|
||||
- title: Looking for Longest Subsequence Instead of Maximum Sum
|
||||
description: |
|
||||
This problem looks like LIS but the goal is different. In LIS, we count elements. Here, we sum scores.
|
||||
|
||||
If you use LIS logic directly (`dp[i] = max length`), you'll get the team with the most players, not the highest score. A team of 2 high-scoring players can beat a team of 5 low-scoring players.
|
||||
wrong_approach: "Count players in valid subsequence"
|
||||
correct_approach: "Sum scores in valid subsequence"
|
||||
|
||||
- title: Misunderstanding the Conflict Rule
|
||||
description: |
|
||||
A conflict only exists when a **younger** player has a **strictly higher** score. Same age never causes conflicts, and equal or lower scores don't cause conflicts.
|
||||
|
||||
Be careful with the inequality: it's `score[younger] > score[older]` that's forbidden, not `>=`.
|
||||
wrong_approach: "Treating equal scores as conflicts"
|
||||
correct_approach: "Only strictly higher scores from younger players cause conflicts"
|
||||
|
||||
key_takeaways:
|
||||
- "**Reduce dimensions via sorting**: Sorting by one attribute lets you focus on the other, turning 2D constraints into 1D problems"
|
||||
- "**LIS variant pattern**: Many problems involve finding optimal subsequences with constraints — recognize when LIS-style DP applies"
|
||||
- "**Secondary sort keys matter**: When primary keys are equal, the secondary sort order affects correctness"
|
||||
- "**Sum vs count**: This is maximum sum subsequence, not longest — the DP state tracks cumulative value, not length"
|
||||
|
||||
time_complexity: "O(n^2). After O(n log n) sorting, we have nested loops: for each of the n players, we check all previous players."
|
||||
space_complexity: "O(n). We store the sorted player list and the DP array, both of size n."
|
||||
|
||||
solutions:
|
||||
- approach_name: Dynamic Programming with Sorting
|
||||
is_optimal: true
|
||||
code: |
|
||||
def best_team_score(scores: list[int], ages: list[int]) -> int:
|
||||
n = len(scores)
|
||||
# Combine age and score, sort by age then score
|
||||
players = sorted(zip(ages, scores))
|
||||
|
||||
# dp[i] = max score of valid team ending with player i
|
||||
dp = [0] * n
|
||||
|
||||
for i in range(n):
|
||||
# Player i alone is a valid team
|
||||
dp[i] = players[i][1] # score of player i
|
||||
|
||||
# Try extending from all previous players
|
||||
for j in range(i):
|
||||
# No conflict if previous player's score <= current score
|
||||
# (age is already guaranteed: players[j].age <= players[i].age)
|
||||
if players[j][1] <= players[i][1]:
|
||||
dp[i] = max(dp[i], dp[j] + players[i][1])
|
||||
|
||||
# Best team could end at any player
|
||||
return max(dp)
|
||||
explanation: |
|
||||
**Time Complexity:** O(n^2) — Nested loops over n players after sorting.
|
||||
|
||||
**Space Complexity:** O(n) — Storage for sorted players and DP array.
|
||||
|
||||
By sorting players by (age, score), we ensure that when we process player `i`, all previous players `j` are no older. The conflict condition simplifies to checking if `score[j] <= score[i]`. We track the maximum sum achievable ending at each player, then return the global maximum.
|
||||
|
||||
- approach_name: Brute Force (Exponential)
|
||||
is_optimal: false
|
||||
code: |
|
||||
def best_team_score(scores: list[int], ages: list[int]) -> int:
|
||||
n = len(scores)
|
||||
max_score = 0
|
||||
|
||||
# Try all 2^n subsets
|
||||
for mask in range(1, 1 << n):
|
||||
team_scores = []
|
||||
team_ages = []
|
||||
|
||||
# Extract players in this subset
|
||||
for i in range(n):
|
||||
if mask & (1 << i):
|
||||
team_scores.append(scores[i])
|
||||
team_ages.append(ages[i])
|
||||
|
||||
# Check for conflicts
|
||||
valid = True
|
||||
for i in range(len(team_ages)):
|
||||
for j in range(len(team_ages)):
|
||||
if team_ages[i] < team_ages[j] and team_scores[i] > team_scores[j]:
|
||||
valid = False
|
||||
break
|
||||
if not valid:
|
||||
break
|
||||
|
||||
if valid:
|
||||
max_score = max(max_score, sum(team_scores))
|
||||
|
||||
return max_score
|
||||
explanation: |
|
||||
**Time Complexity:** O(2^n * n^2) — Enumerate all subsets, check each for conflicts.
|
||||
|
||||
**Space Complexity:** O(n) — Storage for current team being checked.
|
||||
|
||||
This approach tries every possible team composition and validates each one. With n up to 1000, this is completely infeasible (2^1000 subsets). Included to illustrate why the DP approach is necessary.
|
||||
Reference in New Issue
Block a user