DSA Graphs

Longest Cycle in a Graph

In a functional graph (out-degree 1), DFS each node with timestamps; revisiting a current-DFS node closes a cycle.

Hard
Time O(n) Space O(n)
LeetCode
4 min read
graph cycle-detection functional-graph

Problem#

A directed graph where each node has at most one outgoing edge — edges[i] is the next node from i, or -1. Return the length of the longest cycle, or -1 if no cycle exists.

Examples#

  • edges = [3,3,4,2,3]3
  • edges = [2,-1,3,1]-1

Constraints#

  • n == edges.length, 2 <= n <= 10^5, -1 <= edges[i] < n, edges[i] != i.

Approach#

Each node has at most one outgoing edge, so the graph is a forest of “rho” shapes: tails leading into cycles. Walk forward from each unvisited node, tagging visit timestamps. If we hit a node visited in the current walk, the cycle length is currentTime - startTime. If we hit a previously visited node, stop.

Solution#

Longest Cycle in a Graph
class Solution {
public:
int longestCycle(vector<int>& edges) {
int n = edges.size();
vector<int> visitTime(n, 0);
int timer = 1, best = -1;
for (int start = 0; start < n; ++start) {
if (visitTime[start]) continue;
int u = start, startTime = timer;
while (u != -1 && !visitTime[u]) {
visitTime[u] = timer++;
u = edges[u];
}
if (u != -1 && visitTime[u] >= startTime) {
best = max(best, timer - visitTime[u]);
}
}
return best;
}
};

Editorial#

The functional-graph structure means each node belongs to at most one cycle. The “current walk started at timestamp startTime” trick distinguishes a cycle in the current chain (cycle length = current timer minus the revisited node’s timestamp) from a tail merging into a previously explored cycle.

Complexity#

  • Time: O(n).
  • Space: O(n).

Concept revision#

Search ESC

Keyboard shortcuts

Shortcuts are disabled while typing in inputs.