Woodyiiiiiii / LeetCode

My private record of Leetcode solution

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Leetcode 1976. Number of Ways to Arrive at Destination

Woodyiiiiiii opened this issue · comments

这道题我一开始直接用BFS做,没用PQ,然后报错了。看了解析才知道,要结合PQ,说明我对BFS+PQ的理解还是不够深入,不知道什么时候用PQ以及为什么要用PQ。

总结如下:这种在图中要求找到一个顶点到另一个顶点的最短路径之类的题型,都可以用BFS+PQ来做,其中BFS+PQ结合起来就是Dijkstra算法!

可以总结以下题目找到规律:

为什么要用PQ而不是普通的队列Queue呢,以此题为例,case是

6
[[3,0,4],[0,2,3],[1,2,2],[4,1,3],[2,5,5],[2,3,1],[0,4,1],[2,4,6],[4,3,1]]

画完图,然后在Queue代码的情况下跑一下:

public int countPaths(int n, int[][] roads) {
        // convert roads to graph
        Map<Long, List<long[]>> graph = new HashMap<>();
        for (int[] road : roads) {
            long from = road[0];
            long to = road[1];
            long cost = road[2];
            graph.putIfAbsent(from, new ArrayList<>());
            graph.get(from).add(new long[]{to, cost});
            graph.putIfAbsent(to, new ArrayList<>());
            graph.get(to).add(new long[]{from, cost});
        }

        // bfs
        Queue<long[]> queue = new LinkedList<>();
//        PriorityQueue<long[]> queue = new PriorityQueue<>((o1, o2) -> o2[1] - o1[1] >= 0 ? -1 : 1);
        long[][] dist = new long[n][2];
        for (int i = 0; i < n; i++) {
            dist[i][0] = Long.MAX_VALUE;
            dist[i][1] = 0;
        }
        dist[0][0] = 0;
        dist[0][1] = 1;
        final int mod = (int)1e9 + 7;

        queue.offer(new long[]{0, 0});
        while (!queue.isEmpty()) {
            long[] cur = queue.poll();
            if (!graph.containsKey(cur[0])) continue;
            for (long[] next : graph.get(cur[0])) {
                int nextNode = (int) next[0];
                int nextCost = (int) next[1];
                if (nextCost + cur[1] < dist[nextNode][0]) {
                    dist[nextNode][1] = dist[(int) cur[0]][1];
                    dist[nextNode][0] = nextCost + cur[1];
                    queue.offer(new long[]{nextNode, dist[nextNode][0]});
                } else if (nextCost + cur[1] == dist[nextNode][0]) {
                    dist[nextNode][1] += dist[(int) cur[0]][1];
                    dist[nextNode][1] %= mod;
//                    queue.offer(new long[]{nextNode, dist[nextNode][0]});
                }
            }
        }
        return (int) dist[n - 1][1];
    }

就会发现,最后答案会变少,因为路径被截断了,在顶点3的情况下,到2后就不再往5前进了,因为之前已经有路径经过,所以停止了,最后结果为1;

而使用PQ后,因为PQ的排序,可以将队列内的路径“齐头并进”,这样上述在顶点3的路径就始终汇总成1条,继续前进。

宏观来说,BFS+PQ的结合,实际上就是用Dijkstra算法求最短路径,然后在运算过程中记录经过次数。

public int countPaths(int n, int[][] roads) {
        // convert roads to graph
        Map<Long, List<long[]>> graph = new HashMap<>();
        for (int[] road : roads) {
            long from = road[0];
            long to = road[1];
            long cost = road[2];
            graph.putIfAbsent(from, new ArrayList<>());
            graph.get(from).add(new long[]{to, cost});
            graph.putIfAbsent(to, new ArrayList<>());
            graph.get(to).add(new long[]{from, cost});
        }

        // bfs
//        Queue<long[]> queue = new LinkedList<>();
        PriorityQueue<long[]> queue = new PriorityQueue<>((o1, o2) -> o2[1] - o1[1] >= 0 ? -1 : 1);
        long[][] dist = new long[n][2];
        for (int i = 0; i < n; i++) {
            dist[i][0] = Long.MAX_VALUE;
            dist[i][1] = 0;
        }
        dist[0][0] = 0;
        dist[0][1] = 1;
        final int mod = (int)1e9 + 7;

        queue.offer(new long[]{0, 0});
        while (!queue.isEmpty()) {
            long[] cur = queue.poll();
            if (!graph.containsKey(cur[0])) continue;
            for (long[] next : graph.get(cur[0])) {
                int nextNode = (int) next[0];
                int nextCost = (int) next[1];
                if (nextCost + cur[1] < dist[nextNode][0]) {
                    dist[nextNode][1] = dist[(int) cur[0]][1];
                    dist[nextNode][0] = nextCost + cur[1];
                    queue.offer(new long[]{nextNode, dist[nextNode][0]});
                } else if (nextCost + cur[1] == dist[nextNode][0]) {
                    dist[nextNode][1] += dist[(int) cur[0]][1];
                    dist[nextNode][1] %= mod;
//                    queue.offer(new long[]{nextNode, dist[nextNode][0]});
                }
            }
        }
        return (int) dist[n - 1][1];
    }