图中的最长环
难度:
标签:
题目描述
给你一个 n
个节点的 有向图 ,节点编号为 0
到 n - 1
,其中每个节点 至多 有一条出边。
图用一个大小为 n
下标从 0 开始的数组 edges
表示,节点 i
到节点 edges[i]
之间有一条有向边。如果节点 i
没有出边,那么 edges[i] == -1
。
请你返回图中的 最长 环,如果没有任何环,请返回 -1
。
一个环指的是起点和终点是 同一个 节点的路径。
示例 1:
输入:edges = [3,3,4,2,3] 输出去:3 解释:图中的最长环是:2 -> 4 -> 3 -> 2 。 这个环的长度为 3 ,所以返回 3 。
示例 2:
输入:edges = [2,-1,3,1] 输出:-1 解释:图中没有任何环。
提示:
n == edges.length
2 <= n <= 105
-1 <= edges[i] < n
edges[i] != i
代码结果
运行时间: 134 ms, 内存: 27.8 MB
// Problem: Given a directed graph represented by an array edges where each node has at most one outgoing edge,
// find the length of the longest cycle in the graph. Return -1 if no cycle exists.
// Java solution using Streams:
// Similar to the previous approach, but we will use Java Streams to create arrays and iterate through the nodes.
import java.util.stream.IntStream;
public class Solution {
public int longestCycle(int[] edges) {
int n = edges.length;
boolean[] visited = new boolean[n];
int[] distance = IntStream.range(0, n).map(i -> -1).toArray();
final int[] longest = {-1};
IntStream.range(0, n).forEach(i -> {
if (!visited[i]) {
int current = i, dist = 0;
while (current != -1 && !visited[current]) {
visited[current] = true;
distance[current] = dist++;
current = edges[current];
}
if (current != -1 && visited[current] && distance[current] >= 0) {
longest[0] = Math.max(longest[0], dist - distance[current]);
}
}
});
return longest[0];
}
}
解释
方法:
题解使用了一个遍历标记法来检测并记录图中的环。首先,定义一个数组 times 来存储每个节点第一次被访问的时间。遍历图中的每个节点,如果节点已经被访问过,则跳过。对于未访问的节点,从该节点出发,遍历其路径。如果遇到已经访问过的节点,检查这个节点的访问时间是否在当前搜索开始之后,如果是,说明找到了一个环,并用当前时间减去该节点的访问时间来计算环的长度,更新最大环长。若遇到的已访问节点不在当前搜索开始之后,表示此次搜索没有发现新的环,停止当前路径的搜索。这个过程重复直到所有节点都被检查。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
题解中提到`如果访问过当前节点`,然后检查`如果times[x] >= start_time`来判断是否形成了环。这里的逻辑是否意味着只有在当前的搜索路径中访问过的节点才能形成环?
▷🦆
在处理节点i没有出边的情况(即`edges[i] == -1`)时,题解中的逻辑是如何确保不会错误地继续搜索或者错误地计算环的长度?
▷🦆
题解算法在检测到环的情况下是如何确保及时退出当前路径搜索的?是否有可能在环被检测后仍然继续无用的遍历?
▷