寻找图中是否存在路径【LC1971】
There is a bi-directional graph with
n
vertices, where each vertex is labeled from0
ton - 1
(inclusive). The edges in the graph are represented as a 2D integer arrayedges
, where eachedges[i] = [ui, vi]
denotes a bi-directional edge between vertexui
and vertexvi
. Every vertex pair is connected by at most one edge, and no vertex has an edge to itself.You want to determine if there is a valid path that exists from vertex
source
to vertexdestination
.Given
edges
and the integersn
,source
, anddestination
, returntrue
if there is a valid path fromsource
todestination
, orfalse
otherwise*.*
2022/12/19
开始补昨天的
-
思路:使用BFS寻找是否存在目的地到终点的有效路径,从
source
开始按照层次依次遍历每一层的顶点,判断是否可以达到destination
-
实现:
- 首先构建邻接表
adList
,然后使用队列存储最近访问过的顶点,并使用boolean数组isUsed
记录每个顶点的访问状态。 - 初始时将source设为已访问,并且将其加入队列。之后每次将队列中的节点出队,并将其能够到达的未访问过的节点入队。如果访问到
destination
,则直接返回true
;如果队列为空,仍未访问到destination
,则返回false
class Solution { public boolean validPath(int n, int[][] edges, int source, int destination) { boolean[] isUsed = new boolean[n]; List<Integer>[] adList = new List[n]; Deque<Integer> deque = new LinkedList<>(); // 初始化邻接表 for (int i = 0; i < n; i++){ adList[i] = new ArrayList<Integer>(); } for (int[] edge : edges){ int u = edge[0], v = edge[1]; adList[u].add(v); adList[v].add(u); } // 添加起点 deque.add(source); isUsed[source] = true; // BFS搜索 while (!deque.isEmpty()){ int u = deque.pollFirst(); if (u == destination){ return true; } for (Integer next : adList[u]){ if (!isUsed[next]){ deque.addLast(next); isUsed[next] = true; } } } return false; } }
- 复杂度分析
- 时间复杂度: O ( n + m ) O(n+m) O(n+m), n n n为图中顶点的数目, m m m为图中边的数目。对于图中的每个顶点或者每条边,我们最多只需访问一次,因此时间复杂度为 O ( n + m ) O(n+m) O(n+m)。
- 空间复杂度: O ( n + m ) O(n+m) O(n+m),空间复杂度主要取决于邻接表、记录每个顶点访问状态的数组和队列,邻接顶点列表需要的空间为 O ( n + m ) O(n+m) O(n+m),记录访问状态需要 O ( n ) O(n) O(n)的空间,进行广度优先搜索时队列中最多只有 n n n个元素,因此总的空间复杂度为 O ( n + m ) O(n+m) O(n+m)。
- 首先构建邻接表
并查集
-
思路:使用并查集判断两个节点的连通性,如果在并查集中
source
和destination
的根相同,那么证明两个点连通,否则不连通 -
实现
- 首先初始化并查集,每个节点的根节点均为自身
- 然后构建并查集,使用
join
将每条边的两个节点合并 - 最后判断
source
和destination
的根是否相同,若相同则返回true
class Solution { private int[] father; public boolean validPath(int n, int[][] edges, int source, int destination) { // 初始化并查集 father = new int[n]; for (int i = 0; i < n; i++){ father[i] = i; } // 构建并查集 for (int[] edge : edges){ join(edge[0],edge[1]); } // 判断根是否相同 return isSame(source, destination); } private int find(int u){ if (father[u] != u){ father[u] = find(father[u]); } return father[u]; } private void join (int u, int v){ u = find(u); v = find(v); if (u == v) return; father[v] = u; } private Boolean isSame (int u, int v){ u = find(u); v = find(v); return u == v; } }
- 复杂度分析
- 时间复杂度: O ( n + α ( m ) ∗ m ) O(n+\alpha (m)*m) O(n+α(m)∗m), n n n为图中顶点的数目, m m m为图中边的数目。其中 α \alpha α为阿克曼函数的反函数,其增长极其缓慢,也就是说其单次操作的平均运行时间可以认为是一个很小的常数。
- 空间复杂度: O ( n ) O(n) O(n),空间复杂度主要取决于并查集,并查集需要 O ( n ) O(n) O(n)的空间,因此总的空间复杂度为 O ( n ) O(n) O(n)。