矩阵的最小路径和

矩阵的最小路径和

题目:矩阵的最小路径和

《程序员代码面试指南》第57题 P185 难度:尉★★☆☆

本题看了迪杰斯特拉算法受到了启发,才想出来了。还是太菜了……

经典动态规划方法:

简单来说,就是生成和原矩阵一样大小的矩阵dpdp[i][j]的值表示从(0,0)位置走到(i,j)位置的最小路径和。其中对于第一行第一列的元素,它们的值就是沿着第一行或第一列的累加值(因为只能向右或者向下走)。对于其它位置的元素,它们的值为dp[i][j]=min{dp[i-1][j],dp[i][j-1]}+m[i][j]。最右下角的值就是整个问题的答案。具体过程请参看如下代码中的minPathSum1方法。

public int minPathSum1(int[][] m) {
    if (m == null || m.length == 0 || m[0] == null || m[0].length == 0) {
        return 0;
    }
    int row = m.length;
    int col = m[0].length;
    int[][] dp = new int[row][col];
    dp[0][0] = m[0][0];
    for (int i = 1; i < row; i++) {
        dp[i][0] = dp[i - 1][0] + m[i][0];
    }
    for (int j = 1; j < col; j++) {
        dp[0][j] = dp[0][j - 1] + m[0][j];
    }
    for (int i = 1; i < row; i++) {
        for (int j = 1; j < col; j++) {
            dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + m[i][j];
        }
    }
    return dp[row - 1][col - 1];
}

不过该方法的额外空间复杂度O(M×N)。时间复杂度为O(M×N)。

动态规划经过空间压缩后的方法:

可以将额外空间复杂度降为O(min{M,N}),仅仅使用大小为min{M,N}的arr数组

整个过程其实就是不断滚动更新arr数组,让它依次变成dp矩阵每一行或者每一列的值(看哪个最小),最终变成dp矩阵最后一行or列的值

public int minPathSum2(int[][] m) {
    if (m == null || m.length == 0 || m[0] == null || m[0].length == 0) {
        return 0;
    }
    int more = Math.max(m.length, m[0].length); // 行数与列数较大的那个为more
    int less = Math.min(m.length, m[0].length); // 行数与列数较小的那个为less
    boolean rowmore = more == m.length; // 行数是不是大于等于列数
    int[] arr = new int[less]; // 辅助数组的长度仅为行数与列数中的最小值
    arr[0] = m[0][0];
    for (int i = 1; i < less; i++) {
        arr[i] = arr[i - 1] + (rowmore ? m[0][i] : m[i][0]);
    }
    for (int i = 1; i < more; i++) {
        arr[0] = arr[0] + (rowmore ? m[i][0] : m[0][i]);
        for (int j = 1; j < less; j++) {
            arr[j] = Math.min(arr[j - 1], arr[j])
                + (rowmore ? m[i][j] : m[j][i]);
        }
    }
    return arr[less - 1];
}

同时,因为二维数组变成了一维数组,所以每次只需要一次寻址程序的常数时间也得到了一定的加速

但是需要注意,如果本题改成“打印具有最小路径和的路径”或其它求最优解的具体路径的问题,这些问题往往需要完整的动态规划表,此时不能用压缩空间的方法。如果只是想求最优解的值,则可以使用。因为空间压缩的方法是滚动更新的,会覆盖之前求解的值,让求解轨迹变得不可回溯

上一篇:java反射


下一篇:vector(相对线程安全) arryList(线程不安全)