Find Champion II
MedPrompt
There are n teams numbered from 0 to n - 1 in a tournament; each team is also a node in a DAG.
You are given the integer n and a 0-indexed 2D integer array edges of length m representing the DAG, where edges[i] = [ui, vi] indicates that there is a directed edge from team ui to team vi in the graph.
A directed edge from a to b in the graph means that team a is stronger than team b and team b is weaker than team a.
Team a will be the champion of the tournament if there is no team b that is stronger than team a.
Return the team that will be the champion of the tournament if there is a unique champion, otherwise, return -1.
Notes
- A cycle is a series of nodes
a1, a2, ..., an, an+1such that nodea1is the same node as nodean+1, the nodesa1, a2, ..., anare distinct, and there is a directed edge from the nodeaito nodeai+1for everyiin the range[1, n]. - A DAG is a directed graph that does not have any cycle.
Example 1:

Input: n = 3, edges = [[0,1],[1,2]]
Output: 0
Explanation: Team 1 is weaker than team 0. Team 2 is weaker than team 1. So the champion is team 0.Example 2:

Input: n = 4, edges = [[0,2],[1,3],[1,2]]
Output: -1
Explanation: Team 2 is weaker than team 0 and team 1. Team 3 is weaker than team 1. But team 1 and team 0 are not weaker than any other teams. So the answer is -1.
Constraints:
1 <= n <= 100m == edges.length0 <= m <= n * (n - 1) / 2edges[i].length == 20 <= edge[i][j] <= n - 1edges[i][0] != edges[i][1]- The input is generated such that if team
ais stronger than teamb, teambis not stronger than teama. - The input is generated such that if team
ais stronger than teamband teambis stronger than teamc, then teamais stronger than teamc.
Approaches
2 approaches with complexity analysis and trade-offs.
This approach involves a straightforward, brute-force check. It iterates through every team one by one. For each team, it scans the entire list of matches (edges) to determine if there is any other team that is stronger. If no such stronger team is found after checking all matches, the team is considered a champion.
Algorithm
- Initialize an empty list
championsto store the IDs of champion teams. - Iterate through each team
ifrom0ton-1. - For each team
i, assume it's a champion by setting a flagisChampiontotrue. - To verify this, iterate through every edge
[u, v]in theedgeslist. - If the current team
iis the weaker team in an edge (i.e.,v == i), it means another teamuis stronger. Thus,icannot be a champion. SetisChampiontofalseand break the inner loop over the edges. - If the inner loop completes and
isChampionremainstrue, it means no team is stronger thani. Addito thechampionslist. - After checking all teams, if the
championslist contains exactly one element, return that element. - Otherwise, return
-1.
Walkthrough
The algorithm maintains a list to store the identified champions. It loops through each team i from 0 to n-1. For each team i, it assumes it's a champion and then verifies this assumption by iterating through all the given edges. Inside the inner loop, for each edge [u, v], it checks if the current team i is the weaker team (i.e., v == i). If i is found to be a weaker team, it cannot be a champion. A flag is set, and the inner loop (over edges) is terminated for the current team i. If the inner loop completes without finding any team stronger than i, then i is confirmed as a champion and is added to our list of champions. After checking all teams, the algorithm examines the size of the champion list. If the list contains exactly one team, that team's ID is returned. Otherwise, if there are zero or more than one champions, -1 is returned.
import java.util.ArrayList;import java.util.List; class Solution { public int findChampion(int n, int[][] edges) { List<Integer> champions = new ArrayList<>(); for (int i = 0; i < n; i++) { boolean isChampion = true; for (int[] edge : edges) { if (edge[1] == i) { isChampion = false; break; } } if (isChampion) { champions.add(i); } } if (champions.size() == 1) { return champions.get(0); } else { return -1; } }}Complexity
Time
O(n * m), where `n` is the number of teams and `m` is the number of edges. The outer loop runs `n` times, and for each team, the inner loop may run up to `m` times.
Space
O(n), where `n` is the number of teams. In the worst-case scenario (a graph with no edges), the `champions` list could store all `n` teams.
Trade-offs
Pros
The logic is simple and directly follows the definition of a champion.
It's easy to implement without requiring complex data structures.
Cons
This approach is inefficient because it repeatedly scans the entire
edgeslist for each team, leading to a higher time complexity.For dense graphs where the number of edges
mis large, the performance degradation is significant compared to more optimal solutions.
A more efficient approach defines a champion in graph terms: a node with an in-degree of zero. A team is a champion if no other team is stronger, which means there are no incoming edges to its corresponding node in the graph. This method calculates the in-degree for all teams and then identifies the unique team with an in-degree of zero.
Algorithm
- Create an integer array
inDegreeof sizenand initialize all its elements to0. This array will store the number of teams stronger than each team. - Iterate through each edge
[u, v]in theedgeslist once. For each edge, increment the in-degree of the weaker teamv(i.e.,inDegree[v]++). - After populating the
inDegreearray, initialize achampionvariable to-1and achampionCountto0. - Iterate through all teams
ifrom0ton-1. - If
inDegree[i]is0, it means no team is stronger than teami, so it's a champion. IncrementchampionCountand updatechampiontoi. - Finally, check
championCount. If it is1, return thechampion's ID. Otherwise, return-1.
Walkthrough
The core idea is that any team v that appears as the second element in an edge [u, v] has a stronger opponent u and thus cannot be a champion. This is equivalent to saying a champion node must have an in-degree of 0. We can calculate the in-degree for every team. An integer array, inDegree, of size n is initialized to all zeros. We iterate through the edges array just once. For each edge [u, v], we increment the in-degree count for the weaker team v. After processing all the edges, the inDegree array holds the count of stronger opponents for each team. We then iterate through the inDegree array to find the champions. Any team i for which inDegree[i] is 0 is a champion. We count how many such champions exist. If the count is exactly one, we return that champion's ID. Otherwise, we return -1.
class Solution { public int findChampion(int n, int[][] edges) { int[] inDegree = new int[n]; for (int[] edge : edges) { // edge[1] is the weaker team, so its in-degree increases. inDegree[edge[1]]++; } int champion = -1; int championCount = 0; for (int i = 0; i < n; i++) { // A champion has an in-degree of 0. if (inDegree[i] == 0) { championCount++; champion = i; } } // If there is exactly one team with in-degree 0, it's the unique champion. if (championCount == 1) { return champion; } else { // Otherwise, there are multiple champions, so return -1. return -1; } }}Complexity
Time
O(n + m), where `n` is the number of teams and `m` is the number of edges. We perform one pass over the `edges` array (O(m)) and one pass over the teams (O(n)).
Space
O(n), where `n` is the number of teams. This space is used for the `inDegree` array.
Trade-offs
Pros
Highly efficient, with a linear time complexity relative to the size of the input (nodes + edges).
This is the optimal approach as it requires examining each node and edge only once.
Cons
Requires extra space proportional to the number of teams, which could be a consideration for extremely large
n(though not an issue with the given constraints).
Solutions
Solution
class Solution {public int findChampion(int n, int[][] edges) { int[] indeg = new int[n]; for (var e : edges) { ++indeg[e[1]]; } int ans = -1, cnt = 0; for (int i = 0; i < n; ++i) { if (indeg[i] == 0) { ++cnt; ans = i; } } return cnt == 1 ? ans : -1; }}function findChampion ( n , edges ) { const indeg = Array ( n ). fill ( 0 ); for ( const [ _ , v ] of edges ) { ++ indeg [ v ]; } let [ ans , cnt ] = [ - 1 , 0 ]; for ( let i = 0 ; i < n ; ++ i ) { if ( indeg [ i ] === 0 ) { ++ cnt ; ans = i ; } } return cnt === 1 ? ans : - 1 ; }class Solution {public: int findChampion(int n, vector<vector<int>> &edges) { int indeg[n]; memset(indeg, 0, sizeof(indeg)); for (auto &e : edges) { ++indeg[e[1]]; } int ans = -1, cnt = 0; for (int i = 0; i < n; ++i) { if (indeg[i] == 0) { ++cnt; ans = i; } } return cnt == 1 ? ans : -1; }};class Solution: def findChampion(self, n: int, edges: List[List[int]]) -> int: indeg = [0] * n for _, v in edges: indeg[v] += 1 return - 1 if indeg . count(0) != 1 else indeg . index(0)Video walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.