1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| class Solution { public int networkDelayTime(int[][] times, int n, int k) { Map<Integer, List<List<Integer>>> neighborMap = new HashMap<>(); for (int[] time : times) { neighborMap.putIfAbsent(time[0], new ArrayList<>()); neighborMap.get(time[0]).add(new ArrayList<>(Arrays.asList(time[1], time[2]))); } PriorityQueue<Pair<Integer, Integer>> q = new PriorityQueue<>((a, b) -> a.getValue() - b.getValue()); q.offer(new Pair<>(k, 0)); Set<Integer> visited = new HashSet<>(); int ans = -1; while (!q.isEmpty()) { Pair<Integer, Integer> currPair = q.poll(); if (visited.contains(currPair.getKey())) { continue; } visited.add(currPair.getKey()); ans = Math.max(ans, currPair.getValue()); if (visited.size() == n) { return ans; } if (neighborMap.containsKey(currPair.getKey())) { for (List<Integer> neighbor : neighborMap.get(currPair.getKey())) { q.offer(new Pair<>(neighbor.get(0), neighbor.get(1) + currPair.getValue())); } } } return -1; } }
|
Dijkstra’s Algo的应用. 只不过是PQ版本. 这个版本就是把neighors一股脑的都压进queue中. 由于PQ可以把最短的距离移动到头部, 我们每次去的地方都是按照距离start远近的order来的. 如果一个地方被visit过了, 后续PQ中还有表示这个地方的node, 我们就要跳过, 因为这说明其他地方到这个visit的地方距离更远, 否则我们就会先从它那里到这个被visit的地方了. 这点儿和用数组不太一样. 我们是一边走一边更新那个minDistance数组. 然后找下一个地点的时候, 我们遍历数组. 遍历的时候就会判断某个地点是否被visit过. 但是在PQ中, 及时我们在添加的时候判断某个地方有没有被visit过, PQ中还是无法避免同一个地方被添加多次. 因为可能在我们去这个地点前, 有多个其他地点距离start更近, 于是我们会先visit它们, 然而它们都能到达这个同一地点, 于是此时该同一地点就被添加了多次. 因此我们要做的是在node poll出来之后判断是否visit过, 如果有就continue, 没有就说明这个node装的信息就是到达该地点的最近距离.
时间复杂度: O(ElogN) E是edges的个数, N是nodes的个数. PQ size最大就是E, 比如start是中心, 其他nodes只和start相连. 那么push和pop就是O(logE). 由于E最大是n * (n - 1), 因此是O(logn^2)也就是O(2logn)也就是O(logn). 每个node, 我们只会走一遍.也就是我们会把所有的edge都走遍. 于是是O(ElogN)
空间复杂度: O(N^2) 我们用了map存每个node的neighbor信息, 一个node存E个neighors, 一共最多是n * (n - 1)个总edges, 因此是O(N^2), 用set存visit过的node一共是O(N)以及PQ存等待被visit的nodes, 一共是O(E)也就是O(N^2), 加在一起就是O(N^2).