Count Visited Nodes in a Directed Graph - Complete Solution Guide
Count Visited Nodes in a Directed Graph is LeetCode problem 2876, a Hard level challenge. This complete guide provides step-by-step explanations, multiple solution approaches, and optimized code in python3, java, cpp, c.
Problem Statement
There is a directed graph consisting of n nodes numbered from 0 to n - 1 and n directed edges. You are given a 0-indexed array edges where edges[i] indicates that there is an edge from node i to node edges[i] . Consider the following process on the graph: You start from a node x and keep visiting other nodes through edges until you reach a node that you have already visited before on this same process. Return an array answer where answer[i] is the number of different nodes that you will visit if
Detailed Explanation
The problem describes a directed graph where each node has exactly one outgoing edge. Given an array `edges` representing these edges, we need to find, for each starting node `i`, the number of distinct nodes visited before encountering a previously visited node *in the same traversal*. The result is an array `answer` where `answer[i]` is the number of visited nodes starting from node `i`.
Solution Approach
The solution iterates through each node of the graph. For each node, if the answer is already calculated, the solution continues to the next node. Otherwise, it starts traversing the graph from the current node, keeping track of the visited nodes in the current path and their distances from the starting node. If a cycle is detected or a previously computed node is encountered, the solution uses this information to compute the result for all nodes on the current path, and stores the result in the `answer` array.
Step-by-Step Algorithm
- Step 1: Initialize an `answer` array of size `n` with all values set to 0. This array will store the number of visited nodes for each starting node.
- Step 2: Iterate through each node `i` from 0 to `n-1`. If `answer[i]` is not 0, it means the result for node `i` is already computed, so continue to the next node.
- Step 3: For each unvisited node `i`, start traversing the graph. Use a `path` list to store the nodes visited in the current traversal and a `dist` dictionary/map to store the distance of each node from the starting node `i`.
- Step 4: Continue traversing until a cycle is detected (a node is revisited in the current path) or a node with a non-zero value in the `answer` array is encountered.
- Step 5: If a node `curr` with a non-zero value in the `answer` array is encountered, it means a previously computed path has been reached. The number of visited nodes for each node in the current path is then calculated by adding the remaining path length from that node to the value of `answer[curr]` (the already computed length).
- Step 6: If a cycle is detected, identify the starting node of the cycle `cycle_start_index`. The length of the cycle `cycle_len` is the difference between the current path length and `cycle_start_index`.
- Step 7: Set `answer[node]` to `cycle_len` for each node in the cycle.
- Step 8: For nodes in the tail (nodes before the start of the cycle), set `answer[node]` to `(cycle_start_index - j) + cycle_len`, where `j` is the index of the node in the `path` list.
Key Insights
- Insight 1: The graph structure guarantees that starting from any node, you will eventually enter a cycle.
- Insight 2: The problem can be solved by detecting cycles and tail lengths associated with each starting node.
- Insight 3: Memoization (dynamic programming) is crucial to avoid redundant calculations when multiple starting nodes lead to the same cycle.
Complexity Analysis
Time Complexity: O(n)
Space Complexity: O(n)
Topics
This problem involves: Dynamic Programming, Graph, Memoization.
Companies
Asked at: BNY Mellon.