「这是我参与11月更文挑战的第21天,活动详情查看:2021最后一次更文挑战」
描述
节点间通路。给定有向图,设计一个算法,找出两个节点之间是否存在一条路径。
- 示例 1:
输入:n = 3, graph = [[0, 1], [0, 2], [1, 2], [1, 2]], start = 0, target = 2
输出:true
- 示例 2:
输入: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
输出 true
- 提示:
- 节点数量n在[0, 1e5]范围内。
- 节点编号大于等于 0 小于 n。
- 图中可能存在自环和平行边。
解析
把二维数组转为List<List> 每个List 记录的是当前节点的下一个节点集合,然后递归 从起始点开始找下一个节点集合是否包含终止节点
class Solution {
private boolean[] visit;
public boolean findWhetherExistsPath(int n, int[][] graph, int start, int target) {
List<Integer>[] arr = helper(graph, n);
visit = new boolean[n];
return DFS(arr, start, target);
}
//使用邻接矩阵表示图
public List<Integer>[] helper(int[][] graph, int n) {
List<Integer>[] arr = new LinkedList[n];
for(int i = 0; i < n; i++)
arr[i] = new LinkedList<>();
for(int i = 0; i < graph.length; i++) {
int from = graph[i][0], to = graph[i][1];
arr[from].add(to);
}
return arr;
}
public boolean DFS(List<Integer>[] arr, int start, int target) {
//递归跳出标志
//成功
if(start == target)
return true;
//标记当前位
visit[start] = true;
for(int num : arr[start]) {
//下一个没有遍历过的,并且遍历结果可以得到start == target
if(!visit[num] && DFS(arr, num, target))
return true;
}
return false;
}
}
运行结果:
执行结果:通过
执行用时:
内存消耗:
- 解法2,使用邻接表和BFS
class Solution {
public boolean findWhetherExistsPath(int n, int[][] graph, int start, int target) {
List<Integer>[] arr = helper(graph, n);
return BFS(arr, n, start, target);
}
//使用邻接矩阵表示图
public List<Integer>[] helper(int[][] graph, int n) {
List<Integer>[] arr = new LinkedList[n];
for(int i = 0; i < n; i++)
arr[i] = new LinkedList<>();
for(int i = 0; i < graph.length; i++) {
int from = graph[i][0], to = graph[i][1];
arr[from].add(to);
}
return arr;
}
public boolean BFS(List<Integer>[] arr, int n, int start, int target) {
Queue<Integer> queue = new LinkedList<>();
boolean[] visit = new boolean[n];
//新加入队列的标记已被访问
visit[start] = true;
queue.add(start);
while(!queue.isEmpty()) {
int index = queue.poll();
//没有可以到达的下一个节点
if(arr[index] == null)
continue;
for(int num : arr[index]) {
//成功退出
if(num == target)
return true;
//已经入队的数据不再重复处理
if(visit[num])
continue;
else {
//新加入队列的标记已被访问
visit[num] = true;
queue.add(num);
}
}
}
return false;
}
}