You are given a directed graph of n
nodes numbered from 0
to n - 1
, where each node has at most one outgoing edge.
The graph is represented with a given 0-indexed array edges
of size n
, indicating that there is a directed edge from node i
to node edges[i]
. If there is no outgoing edge from node i
, then edges[i] == -1
.
Return the length of the longest cycle in the graph. If no cycle exists, return -1
.
A cycle is a path that starts and ends at the same node.
Example 1:
edges = [3,3,4,2,3]
In this example, the graph has 5 nodes. Node 0 points to node 3, node 1 points to node 3, node 2 points to node 4, node 3 points to node 2, and node 4 points to node 3. The longest cycle is 2 -> 4 -> 3 -> 2, which has a length of 3. Thus the answer should be 3.
Example 2:
edges = [2,-1,3,1]
In this case, node 0 points to node 2, node 1 has no outgoing edge, node 2 points to node 3, and node 3 points to node 1. There are no cycles in this graph, so the answer should be -1.
Could you provide an algorithm to find the longest cycle in the given directed graph? What is the time and space complexity of your solution? Can you provide an example of edge cases and how your algorithm handles them?
The most straightforward approach is to iterate through each node and perform a Depth-First Search (DFS) or Breadth-First Search (BFS) to detect cycles starting from that node. For each node, we explore the path until we either find a cycle or reach a dead end (node with no outgoing edge).
def longestCycle_brute_force(edges):
n = len(edges)
max_cycle_length = -1
for start_node in range(n):
visited = [False] * n
path = []
node = start_node
while node != -1 and not visited[node]:
visited[node] = True
path.append(node)
node = edges[node]
if node != -1 and node in path:
cycle_length = len(path) - path.index(node)
max_cycle_length = max(max_cycle_length, cycle_length)
return max_cycle_length
The optimal solution leverages the fact that each node has at most one outgoing edge. We can use a similar DFS approach, but with a more efficient way of tracking visited nodes and calculating cycle lengths.
visited
array to keep track of visited nodes.visited[node] == True
but dist[node]
is still -1), we stop the traversal along that path because it cannot form a new, longer cycle.def longestCycle(edges):
n = len(edges)
visited = [False] * n
max_cycle_length = -1
for start_node in range(n):
if not visited[start_node]:
dist = [-1] * n # Distance from the start node for the current DFS
dist[start_node] = 0
node = start_node
while node != -1 and not visited[node]:
visited[node] = True
next_node = edges[node]
if next_node != -1 and dist[next_node] == -1:
dist[next_node] = dist[node] + 1
node = next_node
if node != -1 and dist[node] != -1:
cycle_length = dist[start_node] - dist[node] +1 if dist[node] < dist[start_node] else dist[node] - dist[start_node] + 1
max_cycle_length = max(max_cycle_length, cycle_length)
return max_cycle_length
visited
and dist
arrays.edges[i] != i
, so self-loops are not possible.