开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 2 天,点击查看活动详情
1129. 颜色交替的最短路径
在一个有向图中,节点分别标记为 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]
提示:
1 <= n <= 100red_edges.length <= 400blue_edges.length <= 400red_edges[i].length == blue_edges[i].length == 20 <= red_edges[i][j], blue_edges[i][j] < n
思路
要求有向图中的最短路径,只需要从起点处开始向后走,第一次走到节点处的距离,即为最短的路径,要找出第一次走到节点的距离,可以使用广度优先搜索BFS。
我们首先需要记录的是,对于一个节点,从红色路径走可以走到哪些节点,从蓝色路径走可以走到哪些节点,我们可以使用一个二维的邻接表来存储节点的邻接节点信息。
还需要注意的是,每次在走到下一步时,我们需要记录此时所走的路径颜色,判断下一步时需要变换路径颜色。若我们已经走过了某个节点,下一次走到该节点时一定不会比已有的路径长度更短,故不需要再次判断。
题解
class Solution {
public int[] shortestAlternatingPaths(int n, int[][] redEdges, int[][] blueEdges) {
List<Integer>[][] adj = new List[n][2];
for(int i = 0; i < n; i++) {
adj[i][0] = new ArrayList<>();
adj[i][1] = new ArrayList<>();
}
for(int[] edge: redEdges) {
adj[edge[0]][0].add(edge[1]);
}
for(int[] edge: blueEdges) {
adj[edge[0]][1].add(edge[1]);
}
int[][] dist = new int[2][n];
Arrays.fill(dist[0], Integer.MAX_VALUE);
Arrays.fill(dist[1], Integer.MAX_VALUE);
Queue<int[]> queue = new ArrayDeque<>();
queue.offer(new int[]{1, 0});
queue.offer(new int[]{0, 0});
dist[0][0] = 0;
dist[1][0] = 0;
while(!queue.isEmpty()) {
int[] tmp = queue.poll();
int color = tmp[0];//走过的的颜色
int idx = tmp[1];
for(int next: adj[idx][color]) {
if(dist[1 ^ color][next] != Integer.MAX_VALUE) {
continue;
}
dist[1 ^ color][next] = dist[color][idx] + 1;
queue.offer(new int[]{1 ^ color, next});
}
}
int[] ans = new int[n];
for(int i = 0; i < n; i++) {
ans[i] = Math.min(dist[0][i], dist[1][i]);
if(ans[i] == Integer.MAX_VALUE) {
ans[i] = -1;
}
}
return ans;
}
}