1. 题目描述
在一个有向图中,节点分别标记为 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
。
示例 1:
输入:n = 3, red_edges = [[0,1],[1,2]], blue_edges = [] 输出:[0,1,-1]
示例 2:
输入:n = 3, red_edges = [[0,1]], blue_edges = [[2,1]] 输出:[0,1,-1]
示例 3:
输入:n = 3, red_edges = [[1,0]], blue_edges = [[2,1]] 输出:[0,-1,-1]
示例 4:
输入:n = 3, red_edges = [[0,1]], blue_edges = [[1,2]] 输出:[0,1,2]
示例 5:
输入:n = 3, red_edges = [[0,1],[0,2]], blue_edges = [[1,0]] 输出:[0,1,1]
提示:
1 <= n <= 100
red_edges.length <= 400
blue_edges.length <= 400
red_edges[i].length == blue_edges[i].length == 2
0 <= red_edges[i][j], blue_edges[i][j] < n
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/shortest-path-with-alternating-colors
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2. 解题分析
由于是求最短路径,第一感是广度优先搜索问题。只不过,在选择邻接节点时要考虑颜色交替的约束条件。
题目描述中提到“还存在自环或平行边”的条件,后者是指在两个节点之间可以存在一条红边和一条蓝边。前者意味着什么?是不是意味着,比如说当沿着某条红边进入某个节点后,该节点出去的边也都是红色,所以直接出去不满足颜色交替的条件,但是该节点有一条蓝色自环边,所以可以先沿这条蓝色自环边绕一圈然后再从红色边出去?这样就意味着在一条路径上是可以重复访问一个节点的?换句话说,只需要关心路径上边的唯一性,不必关心节点是否有重复?这样的话,需要以(inEdgeColor, node)标记唯一性。处理流程如下:
- (None, 0)入队列q,并加入已访问集合visited
- while q is not empty:
- 从队列q中弹出(inEdgeColor, node)
- if inEdgeColor is red:
- 在blue_edges中搜索前进的路
- elif inEdgeColor is red:
- 在red_edges中搜索前进的路
- else: # 仅限于起点
- 在red_edges和blue_edges合集中搜索前进的路
在以下代码实现中,对于后面的if...elif...else做了一点优化,详细参见代码。
3. 代码实现
from typing import List
from collections import deque
class Solution:
def shortestAlternatingPaths(self, n: int, redEdges: List[List[int]], blueEdges: List[List[int]]) -> List[int]:
# Assuming 0 for red, 1 for blue, None for neither 0 nor 1
q = deque([(None,0,0)])
visited = set([None,0])
dist = n * [-1]
while len(q)>0:
inEdgeColor,node,layer = q.popleft()
# if node not in dist:
if dist[node] < 0:
dist[node] = layer
if inEdgeColor != 0:
for edge in redEdges:
if node==edge[0]:
if (0,edge[1]) not in visited:
q.append((0,edge[1],layer+1))
visited.add((0,edge[1]))
if inEdgeColor != 1:
for edge in blueEdges:
if node==edge[0]:
if (1,edge[1]) not in visited:
q.append((1,edge[1],layer+1))
visited.add((1,edge[1]))
return dist
if __name__ == "__main__":
import time
sln = Solution()
n = 3
red_edges = [[0,1],[1,2]]
blue_edges = []
print(sln.shortestAlternatingPaths(n, red_edges, blue_edges))
n = 3
red_edges = [[0,1]]
blue_edges = [[2,1]]
print(sln.shortestAlternatingPaths(n, red_edges, blue_edges))
n = 3
red_edges = [[1,0]]
blue_edges = [[2,1]]
print(sln.shortestAlternatingPaths(n, red_edges, blue_edges))
n = 3
red_edges = [[0,1]]
blue_edges = [[1,2]]
print(sln.shortestAlternatingPaths(n, red_edges, blue_edges))
n = 3
red_edges = [[0,1],[0,2]]
blue_edges = [[1,0]]
print(sln.shortestAlternatingPaths(n, red_edges, blue_edges))
n = 5
red_edges = [[0,1],[3,2],[1,0],[4,3],[2,4]]
blue_edges = [[2,4],[2,2],[1,3]]
print(sln.shortestAlternatingPaths(n, red_edges, blue_edges))
执行用时:60 ms, 在所有 Python3 提交中击败了15.64%的用户
内存消耗:15.2 MB, 在所有 Python3 提交中击败了44.55%的用户
虽然性能拉胯了一点,不过基本一遍做出来了,还是比较满意的。