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] = [from_i, to_i]
denotes that there is a unidirectional edge from from_i
to to_i
in the graph.
Return a list answer
, where answer[i]
is the list of ancestors of the i^th
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.
For example:
If n = 5
and edgeList = [[0,1],[0,2],[0,3],[0,4],[1,2],[1,3],[1,4],[2,3],[2,4],[3,4]]
,
the expected output is [[],[0],[0,1],[0,1,2],[0,1,2,3]]
Explain your approach to solving this problem. What are the time and space complexities of your solution? Can you provide code?
For each node, we can perform a Depth-First Search (DFS) or Breadth-First Search (BFS) to find all the nodes that can reach it. These nodes are its ancestors.
answer
of size n
, where answer[i]
will store the ancestors of node i
.i
from 0
to n - 1
:
i
to find all nodes that can reach i
.i
itself) to answer[i]
.answer
.def get_ancestors_brute_force(n, edges):
adj_list = [[] for _ in range(n)]
for u, v in edges:
adj_list[v].append(u)
answer = [[] for _ in range(n)]
def dfs(node, target, visited):
for neighbor in adj_list[node]:
if neighbor == target:
visited.add(node)
else:
dfs(neighbor, target, visited)
if target in visited:
visited.add(node)
for i in range(n):
visited = set()
for j in range(n):
dfs(j,i,visited)
ancestors = sorted(list(visited))
answer[i] = ancestors
return answer
We can use dynamic programming combined with topological sorting to efficiently determine the ancestors of each node.
ancestors[i]
for each node i
.u
, for each neighbor v
of u
:
u
to the ancestors set of v
.u
to the ancestors of v
.answer
.def get_ancestors_optimal(n, edges):
adj_list = [[] for _ in range(n)]
in_degree = [0] * n
for u, v in edges:
adj_list[u].append(v)
in_degree[v] += 1
queue = [i for i in range(n) if in_degree[i] == 0]
ancestors = [set() for _ in range(n)]
while queue:
u = queue.pop(0)
for v in adj_list[u]:
ancestors[v].add(u)
ancestors[v].update(ancestors[u])
in_degree[v] -= 1
if in_degree[v] == 0:
queue.append(v)
answer = [sorted(list(ancestors[i])) for i in range(n)]
return answer