You are given a positive integer n representing the number of nodes of a Directed Acyclic Graph (DAG). The nodes are numbered from 0 to n - 1 (inclusive).
You are also given a 2D integer array edges, where edges[i] = [fromi, toi] denotes that there is a unidirectional edge from fromi to toi in the graph.
Return a list answer, where answer[i] is the list of ancestors of the ith node, sorted in ascending order.
A node u is an ancestor of another node v if u can reach v via a set of edges.
Example 1:
Input: n = 8, edgeList = [[0,3],[0,4],[1,3],[2,4],[2,7],[3,5],[3,6],[3,7],[4,6]] Output: [[],[],[],[0,1],[0,2],[0,1,3],[0,1,2,3,4],[0,1,2,3]] Explanation: The above diagram represents the input graph. - Nodes 0, 1, and 2 do not have any ancestors. - Node 3 has two ancestors 0 and 1. - Node 4 has two ancestors 0 and 2. - Node 5 has three ancestors 0, 1, and 3. - Node 6 has five ancestors 0, 1, 2, 3, and 4. - Node 7 has four ancestors 0, 1, 2, and 3.
Example 2:
Input: n = 5, edgeList = [[0,1],[0,2],[0,3],[0,4],[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]] Output: [[],[0],[0,1],[0,1,2],[0,1,2,3]] Explanation: The above diagram represents the input graph. - Node 0 does not have any ancestor. - Node 1 has one ancestor 0. - Node 2 has two ancestors 0 and 1. - Node 3 has three ancestors 0, 1, and 2. - Node 4 has four ancestors 0, 1, 2, and 3.
Constraints:
1 <= n <= 10000 <= edges.length <= min(2000, n * (n - 1) / 2)edges[i].length == 20 <= fromi, toi <= n - 1fromi != toiThis approach involves the following steps:
This solution uses a DFS-based topological sort to process each node in a DAG. We represent the graph as an adjacency list and maintain an indegree count. Nodes with no incoming edges are processed first, during which their ancestors are propagated to their children nodes. This is done until all nodes are processed, yielding a set of ancestors which we then convert to a sorted list for each node to meet the problem requirement.
C++
Java
Time Complexity: O(V + E), where V is the number of nodes and E is the number of edges, since we're effectively traversing all nodes and edges.
Space Complexity: O(V + E), due to the storage needed for the graph representation and the ancestors lists.
Here, we reverse the edges in the graph and then perform a DFS for each node to find all reachable nodes, which now represent ancestors. This is an implementation that directly finds ancestors by traversing upwards in the graph via reversed edges:
This solution reverses the direction of edges and applies DFS for each node to find reachable nodes (representing ancestors). Each DFS invocation tracks visited nodes to prevent reprocessing and adds ancestors directly to the current node's list, which is then sorted for output.
C++
Java
Time Complexity: O(V * (V + E)), due to performing DFS from every node and having potential to traverse the full graph per DFS call.
Space Complexity: O(V + E), where V storage comes from graph information and visited nodes tracking.
| Approach | Complexity |
|---|---|
| DFS and Topological Sorting | Time Complexity: O(V + E), where V is the number of nodes and E is the number of edges, since we're effectively traversing all nodes and edges. |
| Reverse Edge DFS | Time Complexity: O(V * (V + E)), due to performing DFS from every node and having potential to traverse the full graph per DFS call. |
All Ancestors of a Node in a Directed Acyclic Graph | 3 Approaches | Leetcode 2192 |codestorywithMIK • codestorywithMIK • 7,755 views views
Watch 9 more video solutions →Practice All Ancestors of a Node in a Directed Acyclic Graph with our built-in code editor and test cases.
Practice on FleetCode