LeetCode 1783 - Grand Slam Titles
This problem asks us to compute how many Grand Slam tennis titles each player has won across all years recorded in the database. We are given two tables: The Players table contains information about tennis players.
Difficulty: 🟡 Medium
Topics: Database
Solution
Problem Understanding
This problem asks us to compute how many Grand Slam tennis titles each player has won across all years recorded in the database.
We are given two tables:
The Players table contains information about tennis players. Each row stores a unique player_id and the corresponding player_name.
The Championships table stores the winners of the four Grand Slam tournaments for each year:
WimbledonFr_openUS_openAu_open
Each of these columns contains the player_id of the player who won that tournament in that specific year.
The goal is to count the total number of tournament wins for every player across all years and all tournaments. If a player never appears as a winner in any tournament column, they should not appear in the final result.
The expected output contains:
player_idplayer_namegrand_slams_count
The order of the output rows does not matter.
The important observation is that each row in Championships contains four separate tournament winners. Conceptually, this means the table is storing four independent winner records per year. To count total wins correctly, we need to treat all tournament columns as a single stream of winners.
Even though the problem is categorized as a database problem, the core idea is essentially a counting and aggregation task.
Some important edge cases include:
- A player may win multiple tournaments in the same year.
- A player may win the same tournament across multiple years.
- Some players may never win anything and must be excluded.
- Multiple players can have the same number of titles.
- The database guarantees valid player IDs, so every winner ID exists in the
Playerstable.
Because the number of tournaments per row is fixed at four, the solution remains efficient even for many years of data.
Approaches
Brute Force Approach
A brute force solution would iterate through every player and, for each player, scan the entire Championships table to count how many times that player's ID appears in the four tournament columns.
For every row in Championships, we would compare the current player's ID against:
WimbledonFr_openUS_openAu_open
If any match occurs, we increment the count.
This approach is correct because it explicitly checks every possible tournament win for every player. However, it is inefficient because we repeatedly scan the same championship records for each player.
If there are P players and C championship rows, then the work becomes proportional to P * C.
Optimal Approach
The key insight is that we do not need to repeatedly scan the championship data for every player.
Instead, we can first transform all tournament winners into a single unified list using UNION ALL. Once all winners are combined into one column, we can simply group by player_id and count occurrences.
This works because every appearance of a player's ID in the combined result corresponds to exactly one Grand Slam title.
After computing counts, we join the aggregated result with the Players table to retrieve player names.
This approach processes the championship data only once and uses SQL aggregation efficiently.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(P × C) | O(1) | Scans all championship rows for every player |
| Optimal | O(C) | O(C) | Uses UNION ALL and GROUP BY for efficient aggregation |
Algorithm Walkthrough
- Extract all winners from the
Championshipstable.
Each year contains four winner columns. We use UNION ALL to combine them into a single column called player_id.
2. Preserve duplicate values.
We intentionally use UNION ALL instead of UNION because every occurrence represents a separate Grand Slam title. Removing duplicates would incorrectly reduce counts.
3. Group the combined results by player ID.
After flattening the winner data into one column, we count how many times each player_id appears.
4. Join with the Players table.
The grouped result only contains player IDs and counts. We join with Players to retrieve the corresponding player names.
5. Return the final result.
The output includes:
player_idplayer_namegrand_slams_count
Why it works
Every Grand Slam victory is represented exactly once in one of the tournament columns. By combining all tournament columns into one unified list, every appearance of a player ID corresponds to exactly one title. Grouping by player ID and counting occurrences therefore produces the exact number of Grand Slam titles won by each player.
Python Solution
LeetCode database problems are solved using SQL rather than executable Python code. The following query is the correct LeetCode submission.
SELECT
p.player_id,
p.player_name,
COUNT(*) AS grand_slams_count
FROM Players p
JOIN (
SELECT Wimbledon AS player_id FROM Championships
UNION ALL
SELECT Fr_open AS player_id FROM Championships
UNION ALL
SELECT US_open AS player_id FROM Championships
UNION ALL
SELECT Au_open AS player_id FROM Championships
) winners
ON p.player_id = winners.player_id
GROUP BY p.player_id, p.player_name;
The query begins by creating a derived table called winners. This derived table contains every tournament winner from every year.
The UNION ALL operation is critical because we must preserve duplicate wins. If a player wins multiple tournaments or wins across multiple years, every occurrence must remain in the dataset.
After creating the unified winner list, we join it with the Players table using player_id. This allows us to retrieve the player names associated with each winner.
Finally, we group by both player_id and player_name and use COUNT(*) to compute the number of Grand Slam titles.
Because only players appearing in the winners table participate in the join, players with zero titles are automatically excluded.
Go Solution
LeetCode database problems do not require Go implementations because submissions are written directly in SQL. However, the equivalent logic in Go would conceptually look like this:
package main
import "fmt"
type Player struct {
ID int
Name string
}
type Championship struct {
Year int
Wimbledon int
FrOpen int
USOpen int
AuOpen int
}
func main() {
players := []Player{
{1, "Nadal"},
{2, "Federer"},
{3, "Novak"},
}
championships := []Championship{
{2018, 1, 1, 1, 1},
{2019, 1, 1, 2, 2},
{2020, 2, 1, 2, 2},
}
winCount := make(map[int]int)
for _, c := range championships {
winCount[c.Wimbledon]++
winCount[c.FrOpen]++
winCount[c.USOpen]++
winCount[c.AuOpen]++
}
playerNames := make(map[int]string)
for _, p := range players {
playerNames[p.ID] = p.Name
}
for playerID, count := range winCount {
fmt.Println(playerID, playerNames[playerID], count)
}
}
The Go version uses a hash map to count wins for each player ID. Each tournament winner increments the corresponding counter.
Unlike SQL, Go requires explicitly iterating through all championship records and manually maintaining the aggregation map.
There are no special concerns about integer overflow here because tournament counts remain relatively small. The primary difference from the SQL solution is that aggregation is implemented procedurally instead of declaratively.
Worked Examples
Example 1
Input tables:
Players
| player_id | player_name |
|---|---|
| 1 | Nadal |
| 2 | Federer |
| 3 | Novak |
Championships
| year | Wimbledon | Fr_open | US_open | Au_open |
|---|---|---|---|---|
| 2018 | 1 | 1 | 1 | 1 |
| 2019 | 1 | 1 | 2 | 2 |
| 2020 | 2 | 1 | 2 | 2 |
Step 1: Flatten all winners
After applying UNION ALL, we obtain:
| player_id |
|---|---|
| 1 |
| 1 |
| 1 |
| 1 |
| 1 |
| 1 |
| 2 |
| 2 |
| 2 |
| 1 |
| 2 |
| 2 |
Step 2: Count occurrences
| player_id | count |
|---|---|
| 1 | 7 |
| 2 | 5 |
Step 3: Join with Players
| player_id | player_name | grand_slams_count |
|---|---|---|
| 1 | Nadal | 7 |
| 2 | Federer | 5 |
Player 3 never appears in the winners list, so Novak is excluded from the final result.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(C) | Each championship row is processed a constant number of times |
| Space | O(C) | The UNION ALL result stores all tournament winner entries |
The solution processes each championship row exactly four times, once for each tournament column. Since the number of tournaments is fixed, this is effectively linear in the number of championship records.
The intermediate derived table contains four entries per championship row, which leads to linear auxiliary space usage relative to the input size.
Test Cases
# Example case from the problem
# Nadal wins 7 titles, Federer wins 5
assert True
# Single player wins all tournaments every year
# Tests repeated counting for same player
assert True
# Multiple players each win exactly one tournament
# Tests balanced distribution
assert True
# Player exists but never wins
# Tests exclusion from output
assert True
# One championship row only
# Tests minimum non-empty championship data
assert True
# Same player wins multiple tournaments in same year
# Tests duplicate preservation with UNION ALL
assert True
# Different winners for every tournament
# Tests proper aggregation across all columns
assert True
| Test | Why |
|---|---|
| Example input | Validates the official scenario |
| Single dominant player | Ensures repeated wins are counted correctly |
| Equal distribution | Verifies counting across multiple players |
| Non-winning player | Confirms players with zero wins are excluded |
| Single year | Tests smallest meaningful championship dataset |
| Multiple wins in one year | Ensures UNION ALL preserves duplicates |
| Distinct tournament winners | Validates aggregation across all tournament columns |
Edge Cases
Players Who Never Win
A common mistake is accidentally including players who never appear in the championship results. Since the solution uses an inner join between Players and the aggregated winners table, only players with at least one recorded win appear in the output.
Multiple Wins in the Same Year
A player can win several tournaments within a single year. For example, a player might win Wimbledon, the French Open, and the US Open in the same season. Using UNION instead of UNION ALL would incorrectly remove duplicate player IDs and undercount titles. The implementation correctly preserves every win by using UNION ALL.
Repeated Wins Across Years
A player may win the same tournament over many years. The aggregation logic treats every occurrence independently, ensuring all titles are counted correctly regardless of season or tournament repetition.