Given a directed acyclic graph (DAG) with n vertices labeled from 0 to n - 1, and an array of directed edges graph where graph[i] = [ui, vi] represents a directed edge from node ui to node vi.
Return true if and only if:
Example 1:
Input: n = 3, graph = [[0,1],[0,2]] Output: false Explanation: Not all paths from vertex 0 leads to vertex 2. One possible path is 0 -> 1.
Example 2:
Input: n = 4, graph = [[0,1],[0,2],[1,3],[2,3]] Output: true
Example 3:
Input: n = 4, graph = [[0,1],[0,3],[1,2],[2,1]] Output: false Explanation: There is a cycle between 1 and 2.
Constraints:
1 <= n <= 1040 <= graph.length <= 104graph[i].length == 20 <= ui, vi <= n - 1ui != vi[ui, vi] are distinct.When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
Imagine you're exploring a maze with lots of paths. The brute force approach means trying absolutely every possible route from the start. We continue exploring each route until we either reach the destination or find a dead end.
Here's how the algorithm would work step-by-step:
def all_paths_lead_to_destination_brute_force(number_of_nodes, edges, source, destination):
graph = [[] for _ in range(number_of_nodes)]
for source_node, destination_node in edges:
graph[source_node].append(destination_node)
all_paths = []
def find_all_paths(current_node, current_path):
current_path = current_path + [current_node]
if not graph[current_node]:
all_paths.append(current_path)
return
for neighbor in graph[current_node]:
find_all_paths(neighbor, current_path)
find_all_paths(source, [])
if not all_paths:
if source == destination:
return True
else:
return False
# Check if all paths lead to the destination node
for path in all_paths:
if path[-1] != destination:
return False
# Need to ensure no path dead ends before the destination
for path in all_paths:
if len(path) > 1:
for node_index in range(len(path) -1 ):
node = path[node_index]
if not graph[node]:
return False
return TrueThis problem asks us to check if all paths from a starting point in a graph lead to a specific destination. The optimal approach cleverly combines checking if a destination is reachable with identifying cycles that prevent guaranteed arrival at the destination.
Here's how the algorithm would work step-by-step:
def all_paths_lead_to_destination(number_of_nodes, edges, destination_node):
graph = [[] for _ in range(number_of_nodes)]
for source_node, target_node in edges:
graph[source_node].append(target_node)
# If destination has outgoing edges, no
if graph[destination_node]:
return False
visited = [0] * number_of_nodes
def dfs(current_node):
# If cycle, some path won't reach dest.
if visited[current_node] == 1:
return False
# If already visited, skip.
if visited[current_node] == 2:
return True
visited[current_node] = 1
# If it is a dead end.
if not graph[current_node]:
# Dead end should be the destination.
if current_node != destination_node:
return False
else:
for neighbor in graph[current_node]:
if not dfs(neighbor):
return False
# Mark as completely visited.
visited[current_node] = 2
return True
# Check if all paths from source reach dest.
return dfs(0)| Case | How to Handle |
|---|---|
| Empty graph (n = 0) | Return true because there are no paths to violate the condition. |
| Graph with only one node (n = 1) and no edges | Return true if the destination is that single node; false otherwise. |
| Source node is same as destination node, and it has no outgoing edges. | Return true because all paths trivially lead to the destination (itself). |
| Source node is same as destination node, and it has a self-loop. | Return true because all paths (including infinitely looping ones) lead to the destination. |
| Graph contains a cycle that does not lead to the destination. | Return false as paths following the cycle will not reach the destination. |
| Graph contains a cycle that *does* lead to the destination. | This is acceptable as long as *all* paths, including those within the cycle, eventually lead to the destination. |
| Destination node has outgoing edges. | Return false as there is a path from the destination that doesn't end in the destination. |
| Graph contains disconnected components, source component does not reach destination. | Return false, because the components not connected to the destination will not lead to it. |