There is a bi-directional graph with n
vertices, where each vertex is labeled from 0
to n - 1
(inclusive). The edges in the graph are represented as a 2D integer array edges
, where each edges[i] = [ui, vi]
denotes a bi-directional edge between vertex ui
and vertex vi
. 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 vertex destination
.
Given edges
and the integers n
, source
, and destination
, return true
if there is a valid path from source
to destination
, or false
otherwise.
Example 1:
Input: n = 3, edges = [[0,1],[1,2],[2,0]], source = 0, destination = 2 Output: true Explanation: There are two paths from vertex 0 to vertex 2: - 0 → 1 → 2 - 0 → 2
Example 2:
Input: n = 6, edges = [[0,1],[0,2],[3,5],[5,4],[4,3]], source = 0, destination = 5 Output: false Explanation: There is no path from vertex 0 to vertex 5.
Constraints:
1 <= n <= 2 * 105
0 <= edges.length <= 2 * 105
edges[i].length == 2
0 <= ui, vi <= n - 1
ui != vi
0 <= source, destination <= n - 1
- There are no duplicate edges.
- There are no self edges.
这题给了一个无向的可以有环的图,问你能不能找到一个从src到dst的路径。是一道经典的图的题。图主要就是两种解法,BFS和DFS,其实跟别的BFS/DFS还挺像的,虽然刚开始DFS也没写出来,哎。其实还有union find。
不管是BFS还是DFS,首先得把这个图给表示出来。通常采用adjacency list来表示,在java里就是Map<Integer, List<Integer>>,表示一个节点和它对应的邻居们。于是第一步就是先build好这个map。
接下来需要考虑到因为这个图是可以有环的,所以需要一个visited数组来记录这个节点是否被访问过,每次访问完需要set to true,不然第二次回来的时候就死循环了。
下面就来到了BFS/DFS的环节。写完提交以后发现BFS的效率高于DFS。
DFS
和普通的DFS一样,也是通过一个helper function来进行递归,记得这里要传入visited数组和graph的表示。helper里只需要考虑我们现在拿到一个节点了,我们需要对这个节点进行什么处理。首先,如果当前节点已经是dst了,那不就找到了,直接return true就行。如果这个节点已经被visited了,就说明从这个节点出发最后回到了它自己,那这一条路径就不存在能到dst的路径,就return false(其实这里还是不太确定)。然后就是需要visit这个节点,并对它的所有邻居都进行dfs helper操作,如果任何一个的dfs helper return了true,那当前就return true。最后所有遍历完都没return,那就说明没有,直接return false。
嗯,对于dfs里面的具体操作还是有点没有特别明白,以后需要多多复习。
class Solution {
public boolean validPath(int n, int[][] edges, int source, int destination) {
boolean[] visited = new boolean[n];
Map<Integer, List<Integer>> graph = new HashMap<>();
for (int i = 0; i < edges.length; i++) {
int vertex0 = edges[i][0];
int vertex1 = edges[i][1];
List<Integer> neighbor0 = graph.getOrDefault(vertex0, new ArrayList<>());
neighbor0.add(vertex1);
graph.put(vertex0, neighbor0);
List<Integer> neighbor1 = graph.getOrDefault(vertex1, new ArrayList<>());
neighbor1.add(vertex0);
graph.put(vertex1, neighbor1);
}
return dfs(graph, visited, source, destination);
}
private boolean dfs(Map<Integer, List<Integer>> graph, boolean[] visited, int src, int dst) {
if (src == dst) {
return true;
}
if (visited[src]) {
return false;
}
visited[src] = true;
for (int i : graph.get(src)) {
if (dfs(graph, visited, i, dst)) {
return true;
}
}
return false;
}
}
BFS
写完DFS以后写BFS就感觉比较简单了,感觉没怎么想就哼哧哼哧写出来了。就是普通的BFS解法,用一个int queue来存放vertex,经典的先往queue里放第一个元素,然后while queue is not empty,remove queue里第一个元素,然后把这个元素对应的子元素们放进queue,并进行一些题目specific的操作。这道题的题目specific操作就是查当前节点是不是已经是dst了,如果是dst就可以直接return true了,否则要把它的邻居们都加进queue。这里还有一点需要注意,就是因为这个图是可以有环的,所以每次需要查是否已经visit过这个节点,如果是的话就不需要再加邻居了,所以我取完节点就check有没有visit,只有没有visit才进行后面的所有操作。看了别人的写法,很多都是拿到以后先判断是不是dst,再mark为true,然后对它的邻居遍历的时候只有没visit过的邻居采访进来。我觉得两种方法都可。
class Solution {
public boolean validPath(int n, int[][] edges, int source, int destination) {
boolean[] visited = new boolean[n];
Map<Integer, List<Integer>> graph = new HashMap<>();
for (int i = 0; i < edges.length; i++) {
int vertex0 = edges[i][0];
int vertex1 = edges[i][1];
List<Integer> neighbor0 = graph.getOrDefault(vertex0, new ArrayList<>());
neighbor0.add(vertex1);
graph.put(vertex0, neighbor0);
List<Integer> neighbor1 = graph.getOrDefault(vertex1, new ArrayList<>());
neighbor1.add(vertex0);
graph.put(vertex1, neighbor1);
}
Queue<Integer> queue = new LinkedList<>();
queue.add(source);
while (!queue.isEmpty()) {
int vertex = queue.remove();
if (!visited[vertex]) {
visited[vertex] = true;
if (vertex == destination) {
return true;
}
for (int i : graph.get(vertex)) {
queue.add(i);
}
}
// option 2
// if (vertex == destination) {
// return true;
// }
// visited[vertex] = true;
// for (int i : graph.get(vertex)) {
// if (!visited[i]) {
// queue.add(i);
// }
// }
}
return false;
}
}
然后就是union find的做法,永远也记不住,不想看了,贴个之前的笔记好了:LeetCode 200. Number of Islands_wenyq7的博客-CSDN博客
和两个答案:
LeetCode - The World's Leading Online Programming Learning Platform
LeetCode - The World's Leading Online Programming Learning Platform