I
这题的一个主要问题在于可能会出现相交的路径,比如新增一条【0,3】的路径,后续又出现一条【1,4】的路径,这两条路径就会出现一个相交
解题思路:对每个节点进行BFS,用一个list数组储存每个节点可能出现的下一个节点(因为有多条路径所以有多个下一节点),然后对每个下一节点进行重复的循环查询,指导查询到的节点为n-1说明查询到最后一个节点的路径,这时候经过的路径长度就是当前的最短路径长度,
注:进行BFS可以用一个队列存储节点,同时每次用queue的size来表示当前层的循环,当size减小到0的时候重新更新size(类似于树的层序遍历),然后就可以从路径长度1——n-1的方式逐层查询,直到查找到n-1,同时可以用一个visited数组来标记查询过的点,跳过重复的点,因为已经标记过的节点说明之前已经查询过,再重复查询的话对于查询最短路径没有帮助,得到的路径只会大于之前的查询,没有必要
class Solution {
public int[] shortestDistanceAfterQueries(int n, int[][] queries) {
//存储第i个节点的下一个节点
ArrayList<Integer>[] record = new ArrayList[n];
int[] answer = new int[queries.length];
int len = n - 1;
int cnt = 0;
for (int i = 0; i < n; i++) {
ArrayList<Integer> list = new ArrayList<>();
list.add(i+1);
record[i] = list;
}
for (int i = 0; i < queries.length; i++) {
cnt = 1;
int u = queries[i][0];
int v = queries[i][1];
record[u].add(v);
//开始对更新后的序列进行BFS
int chileRecord = 0; //用来记录每一层有多少个节点
int nextLay = 0; //统计下一层有几个节点
boolean[] visited = new boolean[n];
visited[0] = true;
Deque<Integer> queue = new LinkedList<>();
for (Integer integer : record[0]) {
queue.addLast(integer);
visited[integer] = true;
chileRecord++;
}
//这里更好的处理是在里面再加一个循环,简化掉chilerecord和nextlay,直接用
//queue.size获取每一层的节点树,然后在当前层遍历完后再更新size,进行下一层
while (!queue.isEmpty()) {
int addNum = queue.poll();
chileRecord--;
if (addNum == n - 1) {
answer[i] = cnt;
break;
}
for (int temp : record[addNum]) {
//筛选掉已经查询过的节点
if (!visited[temp]) {
queue.addLast(temp);
visited[temp] = true;
nextLay++;
}
}
if (chileRecord == 0) {
cnt++;
chileRecord = nextLay;
nextLay = 0;
}
}
}
return answer;
}
}
II
相比于上一题的区别在于添加了一个通道的约束,从而不会出现两条通道相交的情况,只会出现,一个的终点是另一条通道的起点,或者通道是包含的关系,所以这个题不能使用上面的BFS的方法,会出现超时
解题思路:建立一个数组record来标记每个节点i能到达的下一节点是什么,如果有一个通道是从i到一个更远的终点d,则更新之前i能到达的终点d‘和d之间的节点的下一节点为0,因为有一个更远的终点能够覆盖这些节点,所以这些通道的路径就省了,将d’到d中间的节点的record设置为0,表示如果这个节点的路径被覆盖了,不需要进行操作
class Solution {
public int[] shortestDistanceAfterQueries(int n, int[][] queries) {
//存储第i个节点的下一个节点
int[] record = new int[n];
int[] answer = new int[queries.length];
int len = n - 1;
for (int i = 0; i < n - 1; i++) {
record[i] = i + 1;
}
for (int i = 0; i < queries.length; i++) {
int u = queries[i][0];
int v = queries[i][1];
//大于0保证当前节点是有下一节点的通道,而不是被覆盖了
if (record[u]>0 && record[u] < v) {
for (int l = record[u]; l < v;) {
len--;
int temp = record[l];
record[l] = 0;
l = temp;
}
record[u] = v;
}
answer[i] = len;
}
return answer;
}
}
为什么要有record[u] > 0
如果没有判定大于0,则会出现下面这种,后续的通道已经被之前的通道覆盖,所以没有讨论的意义