2924. Find Champion II
Problem Description
You have n
teams in a tournament, numbered from 0
to n - 1
. These teams form a Directed Acyclic Graph (DAG) where edges represent strength relationships between teams.
Given:
- An integer
n
representing the number of teams - A 2D array
edges
where eachedges[i] = [ui, vi]
means teamui
is stronger than teamvi
(there's a directed edge fromui
tovi
)
In this tournament:
- If there's a directed edge from team
a
to teamb
, it means teama
is stronger than teamb
- A team becomes the champion if no other team is stronger than it
Your task is to find the champion team. Return the team number if there's a unique champion, otherwise return -1
.
The solution uses the concept of in-degrees in a directed graph. The in-degree of a node represents how many edges point to it. In this context:
- If a team has in-degree
0
, no team is stronger than it - If exactly one team has in-degree
0
, that team is the unique champion - If multiple teams have in-degree
0
or no team has in-degree0
, there's no unique champion
The algorithm:
- Create an array
indeg
to count in-degrees for each team - For each edge
[u, v]
, increment the in-degree of teamv
(sinceu
is stronger thanv
) - Check if exactly one team has in-degree
0
- If yes, return that team's index; otherwise return
-1
Intuition
The key insight comes from understanding what it means to be a champion in this tournament structure. A champion is a team that no other team is stronger than. In graph terms, this translates to finding a node that has no incoming edges.
Think about it this way: if a team has an incoming edge, it means there's at least one team stronger than it, so it cannot be the champion. Conversely, a team with no incoming edges has no team stronger than it, making it a potential champion.
Since we're working with a DAG (no cycles), we're guaranteed that at least one node will have no incoming edges. However, the problem asks for a unique champion. This means we need exactly one team with zero in-degree.
Why does counting in-degrees work?
- Each edge
[u, v]
represents "u
beatsv
" - The in-degree of a node tells us how many teams can beat it
- A team with in-degree
0
cannot be beaten by any other team - If only one such team exists, it must be the unique champion
The beauty of this approach is its simplicity: we don't need to traverse the graph or perform complex operations. We just count how many times each team appears as the "loser" (the second element in each edge). The team that never appears as a loser, if unique, is our champion.
This leads directly to the solution: count in-degrees, then check if exactly one team has in-degree 0
.
Learn more about Graph patterns.
Solution Approach
The implementation follows a straightforward approach using in-degree counting:
Step 1: Initialize the in-degree array
indeg = [0] * n
We create an array indeg
of size n
where indeg[i]
will store the in-degree of team i
. Initially, all teams have in-degree 0
.
Step 2: Count in-degrees
for _, v in edges: indeg[v] += 1
We iterate through each edge in the edges
array. For each edge [u, v]
:
- We ignore
u
(the stronger team) since we only care about counting incoming edges - We increment
indeg[v]
by1
because teamv
has one more team stronger than it
Step 3: Check for unique champion
return -1 if indeg.count(0) != 1 else indeg.index(0)
This line does two things:
indeg.count(0)
counts how many teams have in-degree0
(potential champions)- If exactly one team has in-degree
0
, we return its index usingindeg.index(0)
- If the count is not
1
(either0
or more than1
), we return-1
indicating no unique champion
Time Complexity: O(m + n)
where m
is the number of edges and n
is the number of teams
O(m)
to iterate through all edgesO(n)
to count zeros and find the index
Space Complexity: O(n)
for storing the in-degree array
The elegance of this solution lies in its simplicity - by tracking just the in-degrees, we can determine the tournament champion without needing to build or traverse the actual graph structure.
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 4 teams and the following edges:
n = 4
edges = [[0,2], [1,3], [1,2]]
This means:
- Team 0 is stronger than Team 2
- Team 1 is stronger than Team 3
- Team 1 is stronger than Team 2
Step 1: Initialize in-degree array
indeg = [0, 0, 0, 0]
All teams start with in-degree 0.
Step 2: Process each edge to count in-degrees
Processing edge [0,2]
:
- Team 0 beats Team 2, so increment
indeg[2]
indeg = [0, 0, 1, 0]
Processing edge [1,3]
:
- Team 1 beats Team 3, so increment
indeg[3]
indeg = [0, 0, 1, 1]
Processing edge [1,2]
:
- Team 1 beats Team 2, so increment
indeg[2]
indeg = [0, 0, 2, 1]
Step 3: Find the champion
Final in-degree array: [0, 0, 2, 1]
Let's analyze what this means:
- Team 0: in-degree = 0 (no team is stronger)
- Team 1: in-degree = 0 (no team is stronger)
- Team 2: in-degree = 2 (Teams 0 and 1 are stronger)
- Team 3: in-degree = 1 (Team 1 is stronger)
Count teams with in-degree 0: There are 2 teams (Team 0 and Team 1)
Since we have more than one team with in-degree 0, there is no unique champion. The function returns -1
.
Alternative Example with Unique Champion:
Let's modify the edges to [[0,2], [1,3], [1,2], [0,1]]
:
Processing all edges:
[0,2]
:indeg = [0, 0, 1, 0]
[1,3]
:indeg = [0, 0, 1, 1]
[1,2]
:indeg = [0, 0, 2, 1]
[0,1]
:indeg = [0, 1, 2, 1]
Final: indeg = [0, 1, 2, 1]
Only Team 0 has in-degree 0, making it the unique champion. The function returns 0
.
Solution Implementation
1class Solution:
2 def findChampion(self, n: int, edges: List[List[int]]) -> int:
3 # Initialize in-degree array to track incoming edges for each node
4 in_degree = [0] * n
5
6 # Calculate in-degree for each node
7 # For each edge (u, v), increment the in-degree of node v
8 for _, destination in edges:
9 in_degree[destination] += 1
10
11 # Check if there is exactly one node with in-degree 0 (potential champion)
12 # A champion must have no incoming edges (no one beats them)
13 if in_degree.count(0) != 1:
14 # Multiple or no champions found, return -1
15 return -1
16 else:
17 # Return the index of the unique node with in-degree 0
18 return in_degree.index(0)
19
1class Solution {
2 public int findChampion(int n, int[][] edges) {
3 // Create an array to store the in-degree of each node
4 // In-degree represents the number of incoming edges to a node
5 int[] inDegree = new int[n];
6
7 // Calculate in-degree for each node by iterating through all edges
8 // For each edge from node u to node v, increment the in-degree of v
9 for (int[] edge : edges) {
10 inDegree[edge[1]]++;
11 }
12
13 // Initialize variables to track the potential champion and count of nodes with zero in-degree
14 int champion = -1;
15 int zeroInDegreeCount = 0;
16
17 // Iterate through all nodes to find nodes with zero in-degree
18 // A node with zero in-degree has no incoming edges (no one beats them)
19 for (int i = 0; i < n; i++) {
20 if (inDegree[i] == 0) {
21 zeroInDegreeCount++;
22 champion = i;
23 }
24 }
25
26 // Return the champion if there's exactly one node with zero in-degree
27 // Otherwise return -1 (no unique champion exists)
28 return zeroInDegreeCount == 1 ? champion : -1;
29 }
30}
31
1class Solution {
2public:
3 int findChampion(int n, vector<vector<int>>& edges) {
4 // Initialize array to track in-degree for each node
5 // In-degree represents the number of incoming edges to a node
6 int inDegree[n];
7 memset(inDegree, 0, sizeof(inDegree));
8
9 // Calculate in-degree for each node
10 // edges[i] = [from, to] represents a directed edge from 'from' to 'to'
11 for (auto& edge : edges) {
12 ++inDegree[edge[1]]; // Increment in-degree of destination node
13 }
14
15 // Find nodes with zero in-degree (potential champions)
16 // A champion has no incoming edges (no one beats them)
17 int champion = -1;
18 int championCount = 0;
19
20 for (int i = 0; i < n; ++i) {
21 if (inDegree[i] == 0) {
22 ++championCount;
23 champion = i; // Store the potential champion node
24 }
25 }
26
27 // Return the champion if exactly one exists, otherwise return -1
28 // Valid tournament must have exactly one champion
29 return championCount == 1 ? champion : -1;
30 }
31};
32
1/**
2 * Finds the champion node in a directed graph.
3 * A champion is a node with no incoming edges (indegree = 0).
4 * Returns the champion if there's exactly one, otherwise returns -1.
5 *
6 * @param n - The number of nodes in the graph (0 to n-1)
7 * @param edges - Array of directed edges where each edge is [from, to]
8 * @returns The champion node index if unique, otherwise -1
9 */
10function findChampion(n: number, edges: number[][]): number {
11 // Initialize indegree array to track incoming edges for each node
12 const indegreeArray: number[] = Array(n).fill(0);
13
14 // Calculate indegree for each node by iterating through all edges
15 for (const [fromNode, toNode] of edges) {
16 indegreeArray[toNode]++;
17 }
18
19 // Track potential champion and count of nodes with zero indegree
20 let championNode: number = -1;
21 let zeroIndegreeCount: number = 0;
22
23 // Find all nodes with zero indegree
24 for (let nodeIndex = 0; nodeIndex < n; nodeIndex++) {
25 if (indegreeArray[nodeIndex] === 0) {
26 zeroIndegreeCount++;
27 championNode = nodeIndex;
28 }
29 }
30
31 // Return champion only if there's exactly one node with zero indegree
32 return zeroIndegreeCount === 1 ? championNode : -1;
33}
34
Time and Space Complexity
The time complexity is O(n + m)
, where n
is the number of nodes and m
is the number of edges. This breaks down as follows:
- Initializing the
indeg
array takesO(n)
time - Iterating through all edges to update in-degrees takes
O(m)
time - The
count(0)
operation scans through the entireindeg
array, takingO(n)
time - The
index(0)
operation in the worst case also takesO(n)
time - Overall:
O(n) + O(m) + O(n) + O(n) = O(n + m)
Since the problem typically represents a tournament or directed acyclic graph where m
can be at most O(nΒ²)
but is often O(n)
in practice, and considering the reference answer simplifies to O(n)
, this suggests the edges are bounded by O(n)
in the expected case.
The space complexity is O(n)
, as we create an indeg
array of size n
to store the in-degree of each node.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Misunderstanding the Direction of Edges
A frequent mistake is confusing which team is stronger when processing edges. Given an edge [u, v]
, it means team u
is stronger than team v
(not the other way around). This leads to incorrectly incrementing the in-degree.
Incorrect Implementation:
for u, _ in edges: # Wrong! This increments the stronger team's in-degree in_degree[u] += 1
Correct Implementation:
for _, v in edges: # Correct! Increment the weaker team's in-degree in_degree[v] += 1
2. Not Handling Edge Cases Properly
The problem might have special cases that need careful consideration:
- Empty graph with no edges: When
edges = []
andn > 1
, all teams have in-degree 0, so there's no unique champion - Single team: When
n = 1
, that team is automatically the champion regardless of edges
Enhanced Solution with Edge Case Handling:
def findChampion(self, n: int, edges: List[List[int]]) -> int:
# Special case: single team is always champion
if n == 1:
return 0
in_degree = [0] * n
for _, v in edges:
in_degree[v] += 1
# Find all teams with in-degree 0
champions = [i for i in range(n) if in_degree[i] == 0]
# Return champion only if exactly one exists
return champions[0] if len(champions) == 1 else -1
3. Inefficient Champion Detection
Using count()
and index()
separately requires two passes through the array, which can be optimized.
Less Efficient:
if in_degree.count(0) != 1: return -1 else: return in_degree.index(0)
More Efficient Single-Pass Solution:
champion = -1
champion_count = 0
for i in range(n):
if in_degree[i] == 0:
champion = i
champion_count += 1
if champion_count > 1: # Early exit if multiple champions found
return -1
return champion if champion_count == 1 else -1
4. Assuming Graph Connectivity
Don't assume the graph is connected. It's possible to have isolated components or teams that neither beat nor are beaten by certain other teams. The in-degree approach handles this correctly, but it's important to understand that a champion with in-degree 0 might not be able to beat all other teams directly - it just means no team can beat them.
What's the output of running the following function using the following tree as input?
1def serialize(root):
2 res = []
3 def dfs(root):
4 if not root:
5 res.append('x')
6 return
7 res.append(root.val)
8 dfs(root.left)
9 dfs(root.right)
10 dfs(root)
11 return ' '.join(res)
12
1import java.util.StringJoiner;
2
3public static String serialize(Node root) {
4 StringJoiner res = new StringJoiner(" ");
5 serializeDFS(root, res);
6 return res.toString();
7}
8
9private static void serializeDFS(Node root, StringJoiner result) {
10 if (root == null) {
11 result.add("x");
12 return;
13 }
14 result.add(Integer.toString(root.val));
15 serializeDFS(root.left, result);
16 serializeDFS(root.right, result);
17}
18
1function serialize(root) {
2 let res = [];
3 serialize_dfs(root, res);
4 return res.join(" ");
5}
6
7function serialize_dfs(root, res) {
8 if (!root) {
9 res.push("x");
10 return;
11 }
12 res.push(root.val);
13 serialize_dfs(root.left, res);
14 serialize_dfs(root.right, res);
15}
16
Recommended Readings
https assets algo monster cover_photos graph svg Graph Fundamentals Tree with 0 cycle At this point you should be pretty familiar with trees A tree is a special kind of graph a connected acyclic cycle less graph A graph may contain cycle s and nodes could be disconnected A tree
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!