leetcode
leetcode 1151 ~ 1200
无向图中到环的距离

无向图中到环的距离

难度:

标签:

题目描述

代码结果

运行时间: 155 ms, 内存: 49.4 MB


/*
题目思路:
1. 使用BFS来寻找图中的环。首先,通过DFS找出所有的环中的节点。
2. 然后,通过BFS计算每个节点到最近环节点的距离。
3. 返回一个包含所有节点到最近环节点距离的数组。
*/
import java.util.*;
import java.util.stream.*;

class Solution {
    public int[] distanceToCycle(int n, int[][] edges) {
        List<List<Integer>> graph = IntStream.range(0, n)
                                              .mapToObj(i -> new ArrayList<Integer>())
                                              .collect(Collectors.toList());
        for (int[] edge : edges) {
            graph.get(edge[0]).add(edge[1]);
            graph.get(edge[1]).add(edge[0]);
        }

        boolean[] visited = new boolean[n];
        int[] parent = IntStream.generate(() -> -1).limit(n).toArray();
        int[] cycleNodes = IntStream.generate(() -> -1).limit(n).toArray();

        Deque<Integer> queue = new ArrayDeque<>();
        findCycle(0, -1, visited, parent, graph, cycleNodes, queue);

        int[] distances = IntStream.generate(() -> Integer.MAX_VALUE).limit(n).toArray();
        queue.forEach(node -> distances[node] = 0);

        while (!queue.isEmpty()) {
            int node = queue.poll();
            for (int neighbor : graph.get(node)) {
                if (distances[neighbor] == Integer.MAX_VALUE) {
                    distances[neighbor] = distances[node] + 1;
                    queue.offer(neighbor);
                }
            }
        }

        return distances;
    }

    private boolean findCycle(int node, int parent, boolean[] visited, int[] parents, List<List<Integer>> graph, int[] cycleNodes, Deque<Integer> queue) {
        visited[node] = true;
        parents[node] = parent;

        for (int neighbor : graph.get(node)) {
            if (neighbor == parent) continue;
            if (visited[neighbor]) {
                int cur = node;
                while (cur != neighbor) {
                    cycleNodes[cur] = 0;
                    queue.offer(cur);
                    cur = parents[cur];
                }
                cycleNodes[neighbor] = 0;
                queue.offer(neighbor);
                return true;
            }
            if (findCycle(neighbor, node, visited, parents, graph, cycleNodes, queue)) {
                return true;
            }
        }
        return false;
    }
}

解释

方法:

此题解采用了两阶段的广度优先搜索(BFS)来解决问题。首先,第一阶段的BFS用于在无向图中找到一个环,并将环中的节点记录下来。初始时从节点0开始,利用数组`pa`记录每个节点的父节点,以避免向父节点反向遍历,从而检测到环。一旦检测到一个节点被重复访问(即形成环路),则回溯以确定环中的所有节点。第二阶段的BFS从环中的所有节点同时出发,以这些节点作为多源点,计算图中所有其他节点到最近的环中节点的最短距离。这里使用`vis`数组记录节点是否已被访问过,以避免重复处理。

时间复杂度:

O(V + E)

空间复杂度:

O(V + E)

代码细节讲解

🦆
在广度优先搜索中,如何确保不会对同一个节点进行重复访问或处理?
在广度优先搜索(BFS)中,通过使用一个布尔数组`vis`来跟踪每个节点的访问状态来确保不会对同一个节点进行重复访问或处理。在搜索过程开始之前,所有节点的访问状态都设置为`False`。当一个节点第一次被访问时,将其对应在`vis`数组中的值设置为`True`。之后,在遍历该节点的邻接节点时,会首先检查其访问状态,如果已被访问(即`vis`值为`True`),则跳过该节点,这样可以防止同一个节点被重复处理。
🦆
在寻找环的过程中,如果图中存在多个环,该算法如何决定哪个环会被检测到?
该算法从节点0开始执行BFS,因此它将检测到从节点0开始能够首先到达的任何环。如果存在多个环,该算法并不保证找到所有环,而是只关注第一个被检测到的环。环的检测依赖于BFS的遍历顺序和图的结构,一旦发现重复访问的节点即确定一个环,然后通过回溯确定环的完整路径并结束寻找环的过程。因此,哪个环被检测到主要取决于图的连接结构以及BFS的遍历起点。
🦆
为什么在检测到环时,需要对环的完整路径进行回溯,而不是仅仅记录形成环的那两个节点?
在环的检测过程中,仅仅记录形成环的那两个节点是不够的,因为环可能包含多于两个节点的路径。为了确保正确计算图中所有节点到环的最短距离,需要知道环中包含的所有节点。通过回溯可以精确地确定环的全部构成节点,这些节点在之后的多源BFS中被用作起始点来计算距离。如果只记录两个节点,那么可能会遗漏环中的其他节点,从而导致距离的计算不准确。
🦆
在多源BFS执行过程中,如何处理图中孤立节点或与环不连通的节点?
在题解中的多源BFS执行过程中,如果存在孤立节点或与环不连通的节点,这些节点将不会被访问到。这是因为它们不会被环中节点的波及到,因此它们在`vis`数组中的值会保持为`False`,并且在`ans`数组中的值(距离)会保持初始化的默认值(这里题解中未明确初始化为什么值,理论上应该初始化为一个表示无法到达的值,比如正无穷)。因此,这种方法自然地忽略了与环不连通的节点。

相关问题