--- title: "πŸ” Length of Longest Cycle in a Graph | GFG Solution πŸ”" keywords🏷️: ["πŸ” longest cycle", "πŸ” graph traversal", "πŸ“ timestamp marking", "πŸ“ˆ functional graph", "πŸ“˜ GFG", "🏁 competitive programming", "πŸ“š DSA"] author: "✍️ Het Patel (Hunterdii)" description: "βœ… GFG solution to the Length of Longest Cycle in a Graph problem: find the longest cycle in a directed functional graph using iterative timestamp traversal. πŸš€" date: πŸ“… 2025-03-23 --- # *23. Length of Longest Cycle in a Graph* The problem can be found at the following link: πŸ”— [Question Link](https://www.geeksforgeeks.org/problems/length-of-longest-cycle-in-a-graph/1) ## **🧩 Problem Description** Given a **directed graph** with `V` vertices numbered from `0` to `V-1` and `E` edges, represented as a 2D array `edges[][]`, where each entry `edges[i] = [u, v]` denotes a directed edge from `u` to `v`. Each node has **at most one outgoing edge** (functional graph). Your task is to find the **length of the longest cycle** present in the graph. If no cycle exists, return `-1`. > **Note:** A cycle is a path that starts and ends at the same vertex. ## **πŸ“˜ Examples** ### Example 1 ``` Input: V = 7, edges[][] = [[0,5],[1,0],[2,4],[3,1],[4,6],[5,6],[6,3]] Output: 5 Explanation: The longest cycle is 0 β†’ 5 β†’ 6 β†’ 3 β†’ 1 β†’ 0, which has length 5. ``` ### Example 2 ``` Input: V = 8, edges[][] = [[0,1],[1,2],[2,3],[3,0],[4,1],[5,4],[6,2],[7,6]] Output: 4 Explanation: The longest cycle is 0 β†’ 1 β†’ 2 β†’ 3 β†’ 0, which has length 4. ``` ## **πŸ”’ Constraints** * $1 \le V, E \le 10^4$ * $0 \le \text{edges}[i][0], \text{edges}[i][1] < V$ ## **βœ… My Approach** The optimal approach uses **Iterative Timestamp Traversal** β€” a technique specially suited for functional graphs (at most one outgoing edge per node): ### **Timestamp Traversal (Iterative)** 1. **Build Next Array:** * Since every node has at most one outgoing edge, flatten `edges[][]` into a `nxt[]` array where `nxt[u] = v`. Unconnected nodes have `nxt[u] = -1`. 2. **Initialize Visited Array:** * Maintain a `vis[]` array of size `V` initialized to `-1`. Instead of a simple boolean, store the **global timestamp** at which each node was first visited. This lets us measure cycle lengths directly by subtraction. 3. **Traverse Each Component:** * For every unvisited node `i`, record `start = t` (current global time) and walk the chain: assign `vis[cur] = t++`, then follow `nxt[cur]`. * Stop when either: * `cur == -1` β†’ reached a dead end, no cycle in this path. * `vis[cur] != -1` β†’ revisited a node. Two sub-cases: * `vis[cur] >= start` β†’ the revisited node belongs to the **current traversal**, so a cycle exists. Its length is `t - vis[cur]`. * `vis[cur] < start` β†’ the revisited node was already settled in a **previous traversal**; no new cycle here. 4. **Update Answer:** * Whenever a valid cycle is detected, update `ans = max(ans, t - vis[cur])`. 5. **Return Result:** * After all nodes are processed, return `ans`. If no cycle was ever found, `ans` remains `-1`. ## πŸ“ Time and Auxiliary Space Complexity * **Expected Time Complexity:** O(V), as each node is visited at most once across all traversals β€” the global timestamp ensures no node is re-processed. * **Expected Auxiliary Space Complexity:** O(V), as we use a `nxt[]` array of size V to store the functional graph and a `vis[]` array of size V to record visit timestamps. ## **πŸ§‘β€πŸ’» Code (C++)** ```cpp class Solution { public: int longestCycle(int V, vector>& edges) { vector nxt(V, -1); for (auto& e : edges) nxt[e[0]] = e[1]; vector vis(V, -1); int ans = -1, t = 0; for (int i = 0; i < V; i++) { if (vis[i] != -1) continue; int start = t, cur = i; while (cur != -1 && vis[cur] == -1) { vis[cur] = t++; cur = nxt[cur]; } if (cur != -1 && vis[cur] >= start) ans = max(ans, t - vis[cur]); } return ans; } }; ```
⚑ View Alternative Approaches with Code and Analysis ## πŸ“Š **2️⃣ DFS with 3-Color Marking** ### πŸ’‘ Algorithm Steps: 1. Build a `nxt[]` array from edges (functional graph). 2. Color each node: `0` = unvisited, `1` = currently in DFS stack, `2` = fully processed. 3. Track entry time (`tin[]`) for each node when it enters the stack. 4. During DFS, if the next node is already colored `1` (back-edge to active stack), compute cycle length as `t - tin[v]`. ```cpp class Solution { public: int ans = -1; void dfs(int u, vector& nxt, vector& color, vector& tin, int& t) { color[u] = 1; tin[u] = t++; int v = nxt[u]; if (v != -1) { if (color[v] == 0) dfs(v, nxt, color, tin, t); else if (color[v] == 1) ans = max(ans, t - tin[v]); } color[u] = 2; } int longestCycle(int V, vector>& edges) { vector nxt(V, -1), color(V, 0), tin(V, -1); for (auto& e : edges) nxt[e[0]] = e[1]; int t = 0; for (int i = 0; i < V; i++) if (!color[i]) dfs(i, nxt, color, tin, t); return ans; } }; ``` ### πŸ“ **Complexity Analysis:** * **Time:** ⏱️ O(V) β€” Each node is visited exactly once during DFS. * **Auxiliary Space:** πŸ’Ύ O(V) β€” Color array, `tin` array, and implicit recursion stack. ### βœ… **Why This Approach?** * Classic back-edge detection maps naturally to cycle identification. * 3-color scheme clearly distinguishes unvisited, active, and done states. * Easy to reason about and extend for general directed graphs. --- ## πŸ“Š **3️⃣ Topological Sort (Kahn's BFS)** ### πŸ’‘ Algorithm Steps: 1. Build `nxt[]` and compute in-degrees for all nodes. 2. BFS-remove all nodes with in-degree `0` iteratively β€” these nodes can never be part of a cycle. 3. Mark them as `removed`. After BFS, only cycle-participating nodes remain. 4. For each unremoved, unseen node, walk the chain counting nodes until a seen node is hit β€” that count is the cycle length. ```cpp class Solution { public: int longestCycle(int V, vector>& edges) { vector nxt(V, -1), indeg(V, 0); for (auto& e : edges) { nxt[e[0]] = e[1]; indeg[e[1]]++; } queue q; for (int i = 0; i < V; i++) if (!indeg[i]) q.push(i); vector removed(V, false); while (!q.empty()) { int u = q.front(); q.pop(); removed[u] = true; if (nxt[u] != -1 && --indeg[nxt[u]] == 0) q.push(nxt[u]); } int ans = -1; vector seen(V, false); for (int i = 0; i < V; i++) { if (removed[i] || seen[i]) continue; int len = 0, cur = i; while (!seen[cur]) { seen[cur] = true; len++; cur = nxt[cur]; } ans = max(ans, len); } return ans; } }; ``` ### πŸ“ **Complexity Analysis:** * **Time:** ⏱️ O(V) β€” BFS over all nodes + single linear pass over cycle nodes. * **Auxiliary Space:** πŸ’Ύ O(V) β€” In-degree array, removed flags, and BFS queue. ### βœ… **Why This Approach?** * Completely eliminates recursion β€” safe for very large inputs. * Clean two-phase logic: prune non-cycle nodes first, then measure remaining cycles. * Ideal when the graph has a large number of tree/chain nodes leading into cycles. --- ## πŸ†š **πŸ” Comparison of Approaches** | πŸš€ **Approach** | ⏱️ **Time Complexity** | πŸ’Ύ **Space Complexity** | βœ… **Pros** | ⚠️ **Cons** | |---|---|---|---|---| | 🏷️ **Timestamp Traversal** | 🟒 O(V) | 🟒 O(V) | πŸš€ Iterative, minimal code, fastest | πŸ”§ Works only on functional graphs | | 🎨 **3-Color DFS** | 🟒 O(V) | 🟑 O(V) + stack | πŸ“– Intuitive, classic approach | πŸ’Ύ Recursion stack risk on large input | | πŸ”„ **Topological BFS** | 🟒 O(V) | 🟑 O(V) | ⭐ No recursion, clean two-phase logic | 🐌 Two-pass overhead | ### πŸ† **Best Choice Recommendation** | 🎯 **Scenario** | πŸŽ–οΈ **Recommended Approach** | πŸ”₯ **Performance Rating** | |---|---|---| | ⚑ **Maximum performance, competitive programming** | πŸ₯‡ **Timestamp Traversal** | β˜…β˜…β˜…β˜…β˜… | | πŸ“– **Readability / learning** | πŸ₯ˆ **3-Color DFS** | β˜…β˜…β˜…β˜…β˜† | | πŸ”§ **Large input / recursion-safe** | πŸ₯‰ **Topological BFS** | β˜…β˜…β˜…β˜…β˜† | | 🎯 **Interview setting** | πŸ… **Timestamp Traversal** | β˜…β˜…β˜…β˜…β˜… |
## **β˜• Code (Java)** ```java class Solution { public int longestCycle(int V, int[][] edges) { int[] nxt = new int[V]; Arrays.fill(nxt, -1); for (int[] e : edges) nxt[e[0]] = e[1]; int[] vis = new int[V]; Arrays.fill(vis, -1); int ans = -1, t = 1; for (int i = 0; i < V; i++) { if (vis[i] != -1) continue; int start = t, cur = i; while (cur != -1 && vis[cur] == -1) { vis[cur] = t++; cur = nxt[cur]; } if (cur != -1 && vis[cur] >= start) ans = Math.max(ans, t - vis[cur]); } return ans; } } ``` ## **🐍 Code (Python)** ```python class Solution: def longestCycle(self, V, edges): nxt = [-1] * V for u, v in edges: nxt[u] = v vis = [-1] * V ans, t = -1, 0 for i in range(V): if vis[i] != -1: continue start, cur = t, i while cur != -1 and vis[cur] == -1: vis[cur] = t; t += 1; cur = nxt[cur] if cur != -1 and vis[cur] >= start: ans = max(ans, t - vis[cur]) return ans ``` ## 🧠 Contribution and Support For discussions, questions, or doubts related to this solution, feel free to connect on LinkedIn: [πŸ“¬ Any Questions?](https://www.linkedin.com/in/patel-hetkumar-sandipbhai-8b110525a/). Let's make this learning journey more collaborative! ⭐ **If you find this helpful, please give this repository a star!** ⭐ ---

πŸ“Visitor Count

Visitor counter