2225. Find Players With Zero or One Losses
Problem Description
You are given an array matches
where each element matches[i] = [winner_i, loser_i]
represents a match result - player winner_i
defeated player loser_i
.
Your task is to return a list answer
containing exactly 2 lists:
answer[0]
: All players who have never lost any matchesanswer[1]
: All players who have lost exactly one match
Both lists should be sorted in increasing order.
Important constraints:
- Only include players who have played at least one match (either as winner or loser)
- No two matches will have the same outcome (each match result is unique)
For example, if you have matches like [[1,3], [2,3], [3,6], [5,6], [5,7], [4,5], [4,8], [4,9], [10,4], [10,9]]
:
- Players 1, 2, and 10 never lost β
answer[0] = [1, 2, 10]
- Players 4, 5, 7, and 8 lost exactly once β
answer[1] = [4, 5, 7, 8]
- Players 3, 6, and 9 lost more than once, so they don't appear in either list
The solution uses a hash table to count losses for each player. Winners are added to the hash table with 0 losses if not already present, while losers have their loss count incremented. After processing all matches, players are categorized based on their loss count (0 or 1) and sorted before returning.
Intuition
The key insight is that we need to track how many times each player has lost. Since we're looking for players with 0 losses and exactly 1 loss, counting losses is the most direct approach.
When we see a match [winner, loser]
, we know:
- The winner didn't lose this match (but might have lost others)
- The loser definitely lost this match
The tricky part is handling players who only appear as winners. If a player only wins and never appears as a loser in any match, they have 0 losses. This means we need to track all players who participate, not just those who lose.
This leads us to the solution strategy:
- For each match, record the winner with 0 losses (if we haven't seen them before)
- Increment the loser's loss count
- After processing all matches, we'll have a complete record of every player's losses
Why use a hash table? Because we need to:
- Check if we've seen a player before (O(1) lookup)
- Update loss counts efficiently (O(1) update)
- Iterate through all players at the end
The clever part of the solution is using if winner not in cnt: cnt[winner] = 0
. This ensures that players who only win get recorded with 0 losses, while not overwriting the loss count if they've already appeared as a loser in a previous match.
Finally, since we need sorted output and we're categorizing players by loss count (0 or 1), we can iterate through the sorted hash table and append players to ans[0]
or ans[1]
based on their loss count.
Learn more about Sorting patterns.
Solution Approach
The solution uses a hash table (Counter) combined with sorting to efficiently track and categorize players based on their losses.
Step-by-step implementation:
-
Initialize a Counter: We use Python's
Counter()
to create a hash tablecnt
that will store each player's loss count. -
Process each match: For each
[winner, loser]
pair:- Check if the winner is in
cnt
. If not, add them with 0 losses:cnt[winner] = 0
- Increment the loser's loss count:
cnt[loser] += 1
This ensures every player who participates is recorded, with winners starting at 0 losses unless they've lost before.
- Check if the winner is in
-
Initialize result structure: Create
ans = [[], []]
where:ans[0]
will hold players with 0 lossesans[1]
will hold players with 1 loss
-
Categorize players: Iterate through the sorted hash table using
sorted(cnt.items())
:- The sorting ensures players appear in increasing order
- For each player
x
with loss countv
:- If
v < 2
(meaning 0 or 1 losses), append the player toans[v]
- This clever indexing automatically puts 0-loss players in
ans[0]
and 1-loss players inans[1]
- If
-
Return the result: The final
ans
contains two sorted lists as required.
Time Complexity: O(n log n) where n is the number of unique players, due to sorting.
Space Complexity: O(n) for storing the hash table with all unique players.
The elegance of this solution lies in using the loss count as an index (ans[v].append(x)
) when v < 2
, which automatically categorizes players into the correct list without additional conditional logic.
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 with matches: [[1,2], [3,2], [1,4], [3,4]]
Step 1: Initialize Counter
cnt = {}
(empty hash table)
Step 2: Process each match
Match [1,2]:
- Winner is 1, not in
cnt
β addcnt[1] = 0
- Loser is 2 β
cnt[2] = 1
- State:
cnt = {1: 0, 2: 1}
Match [3,2]:
- Winner is 3, not in
cnt
β addcnt[3] = 0
- Loser is 2 β
cnt[2] = 2
(increment from 1) - State:
cnt = {1: 0, 2: 2, 3: 0}
Match [1,4]:
- Winner is 1, already in
cnt
with 0 losses β no change - Loser is 4 β
cnt[4] = 1
- State:
cnt = {1: 0, 2: 2, 3: 0, 4: 1}
Match [3,4]:
- Winner is 3, already in
cnt
with 0 losses β no change - Loser is 4 β
cnt[4] = 2
(increment from 1) - State:
cnt = {1: 0, 2: 2, 3: 0, 4: 2}
Step 3: Categorize players
- Initialize:
ans = [[], []]
- Sort and iterate through
cnt
:[(1,0), (2,2), (3,0), (4,2)]
Process player 1 with 0 losses:
v = 0 < 2
β append 1 toans[0]
- Result:
ans = [[1], []]
Process player 2 with 2 losses:
v = 2
is not < 2 β skip- Result:
ans = [[1], []]
Process player 3 with 0 losses:
v = 0 < 2
β append 3 toans[0]
- Result:
ans = [[1, 3], []]
Process player 4 with 2 losses:
v = 2
is not < 2 β skip- Result:
ans = [[1, 3], []]
Final Answer: [[1, 3], []]
- Players 1 and 3 never lost any matches
- No players lost exactly one match (both 2 and 4 lost twice)
Solution Implementation
1from typing import List
2from collections import Counter
3
4class Solution:
5 def findWinners(self, matches: List[List[int]]) -> List[List[int]]:
6 # Track the number of losses for each player
7 loss_count = Counter()
8
9 # Process each match
10 for winner, loser in matches:
11 # Ensure winner is in the dictionary (with 0 losses if never lost)
12 if winner not in loss_count:
13 loss_count[winner] = 0
14 # Increment loss count for the loser
15 loss_count[loser] += 1
16
17 # Initialize result lists: [players with 0 losses, players with 1 loss]
18 result = [[], []]
19
20 # Sort players by their ID and categorize based on loss count
21 for player_id, losses in sorted(loss_count.items()):
22 # Players with 0 or 1 loss go into respective lists
23 if losses < 2:
24 result[losses].append(player_id)
25
26 return result
27
1class Solution {
2 public List<List<Integer>> findWinners(int[][] matches) {
3 // Map to store the number of losses for each player
4 // Key: player ID, Value: number of losses
5 Map<Integer, Integer> lossCount = new HashMap<>();
6
7 // Process each match
8 for (int[] match : matches) {
9 int winner = match[0];
10 int loser = match[1];
11
12 // Winner has played but not lost this match (ensure they're in the map with 0 losses if new)
13 lossCount.putIfAbsent(winner, 0);
14
15 // Loser gets one more loss added to their count
16 lossCount.merge(loser, 1, Integer::sum);
17 }
18
19 // Initialize result lists:
20 // Index 0: players with 0 losses
21 // Index 1: players with exactly 1 loss
22 List<List<Integer>> result = List.of(new ArrayList<>(), new ArrayList<>());
23
24 // Categorize players based on their loss count
25 for (Map.Entry<Integer, Integer> entry : lossCount.entrySet()) {
26 int player = entry.getKey();
27 int losses = entry.getValue();
28
29 // Add players with 0 or 1 loss to respective lists
30 if (losses < 2) {
31 result.get(losses).add(player);
32 }
33 }
34
35 // Sort both lists in ascending order as required
36 Collections.sort(result.get(0));
37 Collections.sort(result.get(1));
38
39 return result;
40 }
41}
42
1class Solution {
2public:
3 vector<vector<int>> findWinners(vector<vector<int>>& matches) {
4 // Map to track loss count for each player
5 // Key: player ID, Value: number of losses
6 map<int, int> lossCount;
7
8 // Process each match
9 for (auto& match : matches) {
10 int winner = match[0];
11 int loser = match[1];
12
13 // Initialize winner with 0 losses if not already present
14 if (!lossCount.contains(winner)) {
15 lossCount[winner] = 0;
16 }
17
18 // Increment loss count for the loser
19 ++lossCount[loser];
20 }
21
22 // Initialize result with two empty lists
23 // result[0]: players with 0 losses
24 // result[1]: players with exactly 1 loss
25 vector<vector<int>> result(2);
26
27 // Categorize players based on their loss count
28 for (auto& [playerId, losses] : lossCount) {
29 if (losses < 2) {
30 // Add to appropriate list (0 losses or 1 loss)
31 result[losses].push_back(playerId);
32 }
33 }
34
35 return result;
36 }
37};
38
1/**
2 * Finds players with 0 losses and players with exactly 1 loss from match results
3 * @param matches - Array of match results where matches[i] = [winner, loser]
4 * @returns Array containing two arrays: [playersWithNoLosses, playersWithOneLoss]
5 */
6function findWinners(matches: number[][]): number[][] {
7 // Map to track the number of losses for each player
8 const lossCount: Map<number, number> = new Map();
9
10 // Process each match to count losses
11 for (const [winner, loser] of matches) {
12 // Initialize winner with 0 losses if not already tracked
13 if (!lossCount.has(winner)) {
14 lossCount.set(winner, 0);
15 }
16 // Increment loss count for the loser
17 lossCount.set(loser, (lossCount.get(loser) || 0) + 1);
18 }
19
20 // Initialize result arrays: [playersWithNoLosses, playersWithOneLoss]
21 const result: number[][] = [[], []];
22
23 // Categorize players based on their loss count
24 for (const [player, losses] of lossCount) {
25 // Add players with 0 or 1 loss to appropriate array
26 if (losses < 2) {
27 result[losses].push(player);
28 }
29 }
30
31 // Sort both arrays in ascending order
32 result[0].sort((a, b) => a - b);
33 result[1].sort((a, b) => a - b);
34
35 return result;
36}
37
Time and Space Complexity
The time complexity is O(n Γ log n)
, where n
is the number of matches.
- Iterating through all matches to build the counter takes
O(n)
time, where each match contributes two operations (one for the winner check/initialization and one for the loser increment). - The
sorted(cnt.items())
operation sorts the dictionary items by player ID. In the worst case, we could have up to2n
unique players (if every match has two unique players), so sorting takesO(2n Γ log(2n))
=O(n Γ log n)
time. - The final loop to populate the answer lists takes
O(k)
time wherek
is the number of unique players, which is at most2n
. - Overall:
O(n) + O(n Γ log n) + O(n)
=O(n Γ log n)
The space complexity is O(n)
.
- The
cnt
Counter stores at most2n
unique players (in the worst case where all players in all matches are unique), which requiresO(n)
space. - The
ans
list stores the players who lost 0 or 1 match, which in the worst case could be all2n
players, requiringO(n)
space. - The sorting operation may use additional
O(n)
space depending on the implementation. - Overall:
O(n)
space complexity
Learn more about how to find time and space complexity quickly.
Common Pitfalls
Pitfall 1: Forgetting to Track Winners Who Never Lost
The Problem: A common mistake is only adding players to the hash table when they lose a match. This would miss players who only appear as winners and never as losers.
# INCORRECT approach: loss_count = Counter() for winner, loser in matches: loss_count[loser] += 1 # Only tracking losers # This misses winners who never lost!
The Solution: Always check if a winner exists in the hash table. If not, initialize them with 0 losses:
# CORRECT approach: for winner, loser in matches: if winner not in loss_count: loss_count[winner] = 0 # Explicitly track winners loss_count[loser] += 1
Pitfall 2: Not Sorting the Results
The Problem: The problem requires both lists to be sorted in increasing order. Simply iterating through the hash table without sorting would produce unsorted results since hash tables don't maintain order.
# INCORRECT - produces unsorted results: for player_id, losses in loss_count.items(): # No sorting! if losses < 2: result[losses].append(player_id)
The Solution: Sort the items before categorizing:
# CORRECT - ensures sorted output:
for player_id, losses in sorted(loss_count.items()):
if losses < 2:
result[losses].append(player_id)
Pitfall 3: Including Players with More Than One Loss
The Problem: Accidentally including players who lost 2 or more matches in the second list:
# INCORRECT logic: if losses == 0: result[0].append(player_id) else: # This would include players with 2+ losses! result[1].append(player_id)
The Solution:
Use the condition losses < 2
to only include players with 0 or 1 loss:
# CORRECT - filters out players with 2+ losses: if losses < 2: result[losses].append(player_id)
Pitfall 4: Using Default Dictionary Incorrectly
The Problem:
Using defaultdict(int)
might seem convenient, but you still need to ensure winners are added:
# RISKY approach with defaultdict:
from collections import defaultdict
loss_count = defaultdict(int)
for winner, loser in matches:
loss_count[loser] += 1
# Winners aren't explicitly added, relying on iteration over matches
The Solution:
Even with defaultdict
, explicitly handle winners to ensure they're tracked:
loss_count = defaultdict(int)
for winner, loser in matches:
loss_count[winner] += 0 # Ensures winner is in the dict
loss_count[loser] += 1
Which algorithm is best for finding the shortest distance between two points in an unweighted graph?
Recommended Readings
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
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!