题目
在一个有向图中,节点分别标记为 0, 1, …, n-1。图中每条边为红色或者蓝色,且存在自环或平行边。
red_edges 中的每一个 [i, j] 对表示从节点 i 到节点 j 的红色有向边。类似地,blue_edges 中的每一个 [i, j] 对表示从节点 i 到节点 j 的蓝色有向边。
返回长度为 n 的数组 answer,其中 answer[X] 是从节点 0 到节点 X 的红色边和蓝色边交替出现的最短路径的长度。如果不存在这样的路径,那么 answer[x] = -1。
示例
- 输入:n = 5, red_edges = [[0,1],[0,2],[2,3]], blue_edges = [[1,2],[3,4]]
- 输出:[0,1,-1]
题解
这个题目其实方法很容易确定,由于有颜色的交替,因此想到广度优先是很自然的事情。一图胜前言,还是用图说话比较清晰。
上图是一个广度优先遍历的过程,过程比较简单,从初始节点0开始根据交替变幻边的颜色来实现广度优先遍历。下面我们如何实践这个过程来得到最终结果呢?
首先面临的一个问题就是边的表示问题,这里边包含的信息量较多,有源节点,目的节点与颜色。直接用三元组表示不是特别方便,这里城根据源节点找到这些边,hash表是个不错的选择,但这里可更简化一下把源节点作为列表的索引,就剩下目的节点与颜色二元组了。
比如上图中的节点0到1的边可以表示成下面的列表形式,源节点0对应列表中的第0个元素,该元素中的第1个值表示目标节点,第二个值表示边的颜色。
到这里基本上就可以写代码了,代码整理如下:
class Solution:
def shortestAlternatingPaths(self, n: int, redEdges: List[List[int]], blueEdges: List[List[int]]) -> List[int]:
#构建图,图列表的索引表示
g=[[] for _ in range(n)]
for s,t in redEdges:
g[s].append((t,0))
for s,t in blueEdges:
g[s].append((t,1))
dis=[-1]*n
#已遍历过的,由0到0开始,0到0的颜色两种均可加上不会对结构有影响
vis={(0,0),(0,1)}
#广度优先第一层节点初始化
q=[(0,0),(0,1)]
level=0
while q:
next_q=[]
for x,color in q:
if dis[x]==-1:
dis[x]=level
#遍历q中的x节点的下一跳
for p in g[x]:
if p[1]!=color and p not in vis:
vis.add(p)
next_q.append(p)
q=next_q
level+=1
return dis
计算复杂
- 时间复杂度: O ( n + r + b ) O(n+r+b) O(n+r+b),其中 n n n 是节点数,r 是红色边的数目,b是蓝色边的数目。广度优先搜索最多访问一个节点两次,最多访问一条边一次,因此时间复杂度为 O ( n + r + b ) O(n+r+b) O(n+r+b)。
- 空间复杂度: O ( n + r + b ) O(n+r+b) O(n+r+b)。队列中最多有 2n个元素,保存 next 需要 O ( n + r + b ) O(n+r+b) O(n+r+b)的空间,保存 dist需要 O ( n ) O(n) O(n) 的空间。