题目难度: 中等
今天继续更新程序员面试金典系列, 大家在公众号 算法精选 里回复 面试金典 就能看到该系列当前连载的所有文章了, 记得关注哦~
题目描述
节点间通路。给定有向图,设计一个算法,找出两个节点之间是否存在一条路径。
示例 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。
- 图中可能存在自环和平行边。
题目思考
- 需要预处理哪些信息?
- 可以使用哪些算法来判断连通?
解决方案
思路
- 根据题目给定信息, 我们可以得到对应的邻接表, 即
{u:[v1,v2,...,vn]}
字典, 其中 v1,v2,…,vn 是 u 指向的所有节点 - 有了这个邻接表, 我们就可以利用经典的 DFS 或者 BFS 算法来判断是否连通了
- 两个算法思路类似, 都是传入起点, 然后利用邻接表依次遍历相邻的节点, 直到遍历到终点或者遍历完当前的连通分量
- 注意还需要额外的 visit 集合来避免节点重复被遍历
- 下面代码分别提供了 BFS 和 DFS 的方案, 并添加了必要的注释方便大家理解
复杂度
- 时间复杂度 O(N): 每个节点只需要遍历一遍
- 空间复杂度 O(N): 使用了额外 visit 集合
代码
方法 1 - DFS 判断连通
import collections
class Solution:
def findWhetherExistsPath(self, n: int, graph: List[List[int]], start: int,
target: int) -> bool:
# 方法1: 转成邻接表然后DFS判断
if start == target:
# 起点和终点相同, 直接连通
return True
# 先建立邻接表
maps = collections.defaultdict(list)
for x, y in graph:
maps[x].append(y)
# 然后DFS
# 注意使用v集合来避免重复遍历
v = {start}
def dfs(x):
if x == target:
# 当前就是终点, 直接返回true
return True
for nex in maps[x]:
if nex not in v:
v.add(nex)
if dfs(nex):
# 找到终点了
return True
# 没找到终点
return False
return dfs(start)
方法 2 - BFS 判断连通
import collections
class Solution:
def findWhetherExistsPath(self, n: int, graph: List[List[int]], start: int,
target: int) -> bool:
# 方法2: 转成邻接表然后BFS判断
if start == target:
# 起点和终点相同, 直接连通
return True
# 先建立邻接表
maps = collections.defaultdict(list)
for x, y in graph:
maps[x].append(y)
# 然后BFS
q = [start]
v = set(q)
for x in q:
for nex in maps[x]:
if nex == target:
# 这里直接判断nex是否为target, 而不是等遍历到x再判断, 提前加速找终点
return True
if nex not in v:
v.add(nex)
q.append(nex)
return False
大家可以在下面这些地方找到我~😊
我的公众号: 算法精选, 欢迎大家扫码关注~😊