leetcode
leetcode 2751 ~ 2800
节点间通路

节点间通路

难度:

标签:

题目描述

Given a directed graph, design an algorithm to find out whether there is a route between two nodes.

Example1:

 Input: n = 3, graph = [[0, 1], [0, 2], [1, 2], [1, 2]], start = 0, target = 2
 Output: true

Example2:

 Input: n = 5, graph = [[0, 1], [0, 2], [0, 4], [0, 4], [0, 1], [1, 3], [1, 4], [1, 3], [2, 3], [3, 4]], start = 0, target = 4
 Output true

Note:

  1. 0 <= n <= 100000
  2. All node numbers are within the range [0, n].
  3. There might be self cycles and duplicated edges.

代码结果

运行时间: 89 ms, 内存: 53.4 MB


/*
 * 题目思路:
 * 使用Java Stream进行图的DFS实现。通过流式处理减少显式循环的使用。
 * 通过递归的方式来检查从起始节点到目标节点是否存在路径。
 */
import java.util.*;
import java.util.stream.*;

public class SolutionStream {
    public boolean hasPath(int n, int[][] graph, int start, int target) {
        // 使用邻接表表示图
        Map<Integer, List<Integer>> adjList = Arrays.stream(graph)
                .collect(Collectors.groupingBy(
                        edge -> edge[0],
                        Collectors.mapping(edge -> edge[1], Collectors.toList())));

        // 标记节点是否访问过
        boolean[] visited = new boolean[n];
        return dfs(adjList, visited, start, target);
    }

    private boolean dfs(Map<Integer, List<Integer>> adjList, boolean[] visited, int current, int target) {
        if (current == target) {
            return true;
        }
        visited[current] = true;
        return adjList.getOrDefault(current, Collections.emptyList()).stream()
                .filter(neighbor -> !visited[neighbor])
                .anyMatch(neighbor -> dfs(adjList, visited, neighbor, target));
    }
}

解释

方法:

该题解采用了深度优先搜索(DFS)的算法来解决有向图中两个节点之间是否存在路径的问题。首先,构建邻接表来表示图,这由列表 `next` 表示,其中 `next[i]` 包含所有从节点 i 可以直接到达的节点。使用一个标志数组 `flag` 来记录每个节点是否已被访问过,以避免循环访问和重复工作。从起始节点 `start` 开始,使用栈(这里的实现使用列表的 pop 方法模拟栈)来进行深度优先搜索。每次从栈中取出一个节点,检查其所有邻接节点;如果邻接节点是目标节点 `target`,则立即返回 true 表示路径存在。如果不是目标节点且未被访问过,则将其加入栈中并标记为已访问。如果所有可能的路径都检查完毕,栈为空,则返回 false 表示没有路径。

时间复杂度:

O(n + m)

空间复杂度:

O(n + m)

代码细节讲解

🦆
为什么选择深度优先搜索(DFS)而不是广度优先搜索(BFS)来解决这个问题?
DFS和BFS都可以用来解决找出图中两个节点是否存在路径的问题。选择DFS主要是因为其实现简单且在许多情况下能够更快地找到解决方案。DFS通过栈的使用,能够迅速深入探索图中的路径,尤其是在目标节点可能位于图的深层部分时,DFS可能更快地找到路径。此外,DFS在递归形式中编码更为直观。然而,BFS也有其优势,特别是在需要找到最短路径或者图比较宽时,BFS可能会更加高效。总之,本题解选择DFS主要是出于对场景的假设和简化实现的考虑。
🦆
在构建邻接表时,如果存在重复的边(如示例输入中的 [1, 2], [1, 2]),这对算法的执行有什么影响?是否需要在建图时去除重复的边?
在构建邻接表时,如果存在重复的边,这可能导致算法在遍历时重复访问同一条边,从而增加执行时间。在DFS中,虽然可以通过访问标记防止重复访问同一节点,但处理重复边仍然会造成不必要的性能负担。因此,在实际应用中,建议在构建图时去除重复的边。这不仅可以减少存储空间的消耗,还能提高算法的运行效率。
🦆
算法中使用的标志数组 `flag` 仅包含两种状态(未访问和已访问),能否在这个场景中使用颜色标记法(如使用三种颜色标记未访问、正在访问、已访问完成)来帮助检测有向图中的环?
在DFS中使用颜色标记法是一种常见的技术,特别是在需要检测图中是否存在环的场景下。通过三种颜色(通常是白色、灰色和黑色)来表示节点的访问状态:白色代表未访问,灰色代表节点正在被访问(即节点已经进入递归栈中),黑色则表示节点的所有邻接节点都被访问完成,即出栈。这种方法不仅可以帮助检测环,还可以帮助理解递归过程中节点的状态。在本题的场景中,尽管主要目标是确定两个节点间是否存在路径,如果问题扩展到需要确保路径不存在环,那么颜色标记法将非常有用。

相关问题