• 1631.朴素dijkstra/优先队列BFS


    题目链接:https://leetcode-cn.com/problems/path-with-minimum-effort/

    一开始认为是动态规划,但无法初始化,不满足无后效性,排除。贪心也是不可能的,排除。

    想到了最短路解法,dijkstra,来更新dijs数组,使得其最大值最小,然后超时了,过了一半的样例,需要采取更高效的算法。

    import java.util.Arrays;
    
    class Solution {
    
        //节点数
        int n;
        int[][] map;
    
        int dijkstra(int st, int ed) {
            int[] dij = new int[n];
            boolean[] vis = new boolean[n];
            for (int i = 0; i < n; i++) {
                dij[i] = map[st][i];
                vis[i] = false;
            }
            vis[st] = true;
            //最多需要确定n - 1次,因为起点已经确定了
            for (int i = 0; i < n - 1; i++) {
                if (vis[ed])
                    break;
                int minn = 0x3f3f3f3f;
                int v = -1;
                for (int j = 0; j < n; j++) {
                    if (dij[j] < minn && !vis[j]) {
                        minn = dij[j];
                        v = j;
                    }
                }
                vis[v] = true;
                //松弛其他点
                for (int j = 0; j < n; j++) {
                    if (!vis[j]) {
                        dij[j] = Math.min(dij[j], Math.max(dij[v], map[v][j]));
                    }
                }
            }
            return dij[ed];
        }
    
        public int minimumEffortPath(int[][] heights) {
            int row = heights.length;
            int col = heights[0].length;
            n = row * col;
            map = new int[n][n];
            //二维数组map初始化
            for (int i = 0; i < n; i++) {
                for (int j = 0; j < n; j++) {
                    if (i == j)
                        map[i][j] = 0;
                    else
                        map[i][j] = map[j][i] = 0x3f3f3f3f;
                }
            }
            //map数组存相邻节点边权(双向边)
            for (int i = 0; i < row; i++) {
                for (int j = 0; j < col; j++) {
                    int currentNode = i * col + j;
                    int rightNode = currentNode + 1;
                    int downNode = (i + 1) * col + j;
                    if (j != col - 1)
                        map[currentNode][rightNode] = map[rightNode][currentNode] = Math.abs(heights[i][j] - heights[i][j + 1]);
                    if (i != row - 1)
                        map[currentNode][downNode] = map[downNode][currentNode] = Math.abs(heights[i][j] - heights[i + 1][j]);
                    /*if (rightNode < n)
                        System.out.println("节点" + currentNode + "到节点" + rightNode + "的边权为:" + map[currentNode][rightNode]);
                    if (downNode < n)
                        System.out.println("节点" + currentNode + "到节点" + downNode + "的边权为:" + map[currentNode][downNode]);*/
                }
            }
            return dijkstra(0, n - 1);
        }
    }
    方法一:朴素dijkstra

    采用优先队列优化,快速得到当前最小的dij值即可

    import java.util.Arrays;
    import java.util.Comparator;
    import java.util.PriorityQueue;
    
    class Solution {
        public int minimumEffortPath(int[][] heights) {
            //方向数组:上下左右
            int[] dx = new int[]{0, 0, -1, 1};
            int[] dy = new int[]{1, -1, 0, 0};
            int rowNums = heights.length;
            int colNums = heights[0].length;
            int n = rowNums * colNums;
            int[] dij = new int[n];
            Arrays.fill(dij, Integer.MAX_VALUE);
            dij[0] = 0;
            boolean[] vis = new boolean[n];
            Arrays.fill(vis, false);
            //优先队列(从小到大)
            PriorityQueue<int[]> Q = new PriorityQueue<>(new Comparator<int[]>() {
                public int compare(int[] pre, int[] next) {
                    return pre[2] - next[2];
                }
            });
            //所在row下标,所在col下标,dij[x * colNums + y]值
            Q.add(new int[]{0, 0, 0});
            while (!Q.isEmpty()) {
                int[] currentNode = Q.poll();
                int x = currentNode[0];
                int y = currentNode[1];
                int currentId = x * colNums + y;
                vis[currentId] = true;
                if (vis[n - 1])
                    break;
                for (int k = 0; k < 4; k++) {
                    int xx = x + dx[k];
                    int yy = y + dy[k];
                    int nextId = xx * colNums + yy;
                    if (xx >= 0 && xx < rowNums && yy >= 0 && yy < colNums && !vis[nextId]) {
                        if (Math.max(currentNode[2], Math.abs(heights[xx][yy] - heights[x][y])) < dij[nextId]) {
                            dij[nextId] = Math.max(currentNode[2], Math.abs(heights[xx][yy] - heights[x][y]));
                            Q.add(new int[]{xx, yy, dij[nextId]});
                        }
                    }
                }
            }
            return dij[n - 1];
        }
    }
    方法二:BFS优先队列

    献上属于这道题的草稿纸,手动跑朴素dijsktra的过程。通过这个过程发现了

    1.方法一寻找当前最小dij值时的整个循环可以优化成方法二优先队列每次直接弹出最小dij

    2.方法一松弛时对所有点遍历可以优化成方法二方向数组控制的几个邻接点的松弛

  • 相关阅读:
    cpu核数和逻辑个数的区别_CPU逻辑核心数和物理核心数
    linux查看CPU数
    Java读取excel中日期格式结果为数字44326天
    Java实现读取excel中的数据及图片
    jmeter设置全局变量,获取登录token,实现两个线程组参数公用
    CPU使用率
    快照版本和发布版本区别
    jmeter与postman请求结果返回不一致
    接口认证方式:Bearer Token
    jmeter 中报java.lang.OutOfMemoryError: Java heap space
  • 原文地址:https://www.cnblogs.com/yuanweidao/p/14347052.html
Copyright © 2020-2023  润新知