美文网首页
矩阵最小路径和

矩阵最小路径和

作者: stoneyang94 | 来源:发表于2018-08-27 09:12 被阅读0次

题目(算法课第八课)

给你一个二维数组,二维数组中的每个数都是正数,要求从左上角走到右下角,每一步只能向右或者向下。沿途经过的数字要累加起来。返回最小的路径和。

举例

如果给定的m如下,那么路径1,3,1,0,6,1,0就是最小路径和,返回12

1 3 5 9 
8 1 3 4 
5 0 6 1 
8 8 4 0

思路

思路1:递归

每个位置只能向右 或者 向下走,每次走最短的,无后效性。

代码1:

    public static int minPath1(int[][] matrix) {
        return minPath1(matrix, 0, 0);
    }

    public static int minPath1(int[][] matrix, int i, int j) {
        if (i == matrix.length - 1 && j == matrix[0].length - 1) {
            return matrix[i][j];
        }
        if (i == matrix.length - 1 && j != matrix[0].length - 1) {
            return matrix[i][j] + minPath1(matrix, i, j + 1);
        }
        if (j == matrix[0].length - 1 && i != matrix.length - 1) {
            return matrix[i][j] + minPath1(matrix, i + 1, j);
        }
        int right = minPath1(matrix, i, j + 1);
        int down =  minPath1(matrix, i + 1, j);
        return matrix[i][j] + Math.min(right, down);
    }

思路2:动态规划

运用动态规划,我们在递归的时候了解到,(i,j)位置的值依赖它左边或者上边的值,所以我们就先把它依赖的求出来,然后从左上开始向(i,j)求,相当于把递归的过程反过来。申请一个新的二维数组空间,分别求出第一行和第一列的累计和的值,然后再求(i,j)位置的值时就可以根据已经求出的第一行和第一列的累计和来算(把每个i,j位置的路径和都算出来),先找出不被依赖的,再求出依赖的。

步骤

假设矩阵m的大小为M×N,行数为M,列数为N。

1. dp[i][j]

生成大小和m一样的矩阵dp,dp[i][j]的值表示从左上角(即(0,0))位置走到(i ,j)位置的最小路径和。

2. base case

对m的第一行的所有位置来说,即(0,j)(0≤j<N),从(0,0)位置走到(0,j)位置只能向右走,
所以(0,0)位置到(0,j)位置的路径和就是m[0][0..j]这些值的累加结果。

同理,对m的第一列的所有位置来说,即(i,0)(0≤i<M),从(0,0)位置走到(i,0)位置只能向下走,
所以(0,0)位置到(i,0)位置的路径和就是m[0..i][0]这些值的累加结果。

以题目中的例子

1 3 5 9 
8 1 3 4 
5 0 6 1 
8 8 4 0

来说,dp第一行和第一列的值如下:

1   4   9   1   8    
9    
14  
22

3. “补表”

除第一行和第一列,其他位置(i ,j)都有左边位置(i-1,j)和上边位置(i ,j-1)。从(0,0)到(i ,j)的路径必然经过位置(i-1,j)或位置(i ,j-1)——所以

dp[i][j]=min{ dp[i-1][j],dp[i][j-1] }+m[i][j]

含义是比较从(0,0)位置开始,经过(i-1,j)位置最终到达(i,j)的最小路径和经过(i ,j-1)位置最终到达(i ,j)的最小路径之间,哪条路径的路径和更小。
更小的路径和就是dp[i][j]的值。

以题目的例子

1 3 5 9 
8 1 3 4 
5 0 6 1 
8 8 4 0

来说,最终生成的dp矩阵如下:

1   4   9   18         
9   5   8   12         
14  5  11   12         
22 13  15   12 

代码2:

public static int minPath2(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];
    }

总的代码

public class MinPath {
    public static void main(String[] args) {
        int[][] m = { { 1, 3, 5, 9 }, { 8, 1, 3, 4 }, { 5, 0, 6, 1 }, { 8, 8, 4, 0 } };
        System.out.println(minPath1(m));
        System.out.println(minPath2(m));
    }

    public static int minPath1(int[][] matrix) {
        return minPath1(matrix, matrix.length - 1, matrix[0].length - 1);
    }

    public static int minPath1(int[][] matrix, int i, int j) {
        int res = matrix[i][j];
        if (i == 0 && j == 0) {
            return res;
        }
        if (i == 0 && j != 0) {
            return res + minPath1(matrix, i, j - 1);
        }
        if (i != 0 && j == 0) {
            return res + minPath1(matrix, i - 1, j);
        }
        return res + Math.min(minPath1(matrix, i, j - 1), minPath1(matrix, i - 1, j));
    }

    public static int minPath2(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];
    }
}

输出:

12
12

相关文章

  • 矩阵最小路径和

    题目(算法课第八课) 给你一个二维数组,二维数组中的每个数都是正数,要求从左上角走到右下角,每一步只能向右或者向下...

  • 矩阵的最小路径和

    思路:首先要把第一行、第一列进行初始化然后其他位置按照偏移方程dp[i][j] = Math.min(dp[i-1...

  • Python3 欧拉计划 问题81-85

    81、最小路径和(初级)  2个方向   在如下5*5的数字矩阵中,只能向右或向下移动,从左上角到右下角的最小路径...

  • Leetcode 精选之矩阵路径( 最小路径和)

    题目描述 给定一个包含非负整数的 m x n 网格,请找出一条从左上角到右下角的路径,使得路径上的数字总和为最小。...

  • 12_5矩阵最小路径和

    有一个矩阵map,它每个格子有一个权值。从左上角的格子开始每次只能向右或者向下走,最后到达右下角的位置,路径上所有...

  • 经典DP问题合集

    一、上台阶问题 二、矩阵最小路径和 三、最长递增子序列 四、最长公共子序列 五、背包问题

  • 图的最短路径算法(Dijkstra和Floyd)

    最短路径和最小生成树的区别:最短路径解决的是如何求解各顶点之间的路径权值和最小的问题。最小生成树是保证图的所有路径...

  • Pytorch之线性代数

    矩阵 矩阵初始化 矩阵元素运算 矩阵的乘法 矩阵的转置 矩阵对应列行的最大值,最小值,和 矩阵的其他操作:行列数、...

  • 动态规划:二维矩阵最小路径和

    题目:一个二维数组,二维数组中的每个数都是正数,要求从左上角走到右下角,每一步只能向右或者向下,沿途经过的数字要累...

  • 最小路径和

    LintCode题目地址 给定一个只含非负整数的m*n网格,找到一条从左上角到右下角的可以使数字和最小的路径。

网友评论

      本文标题:矩阵最小路径和

      本文链接:https://www.haomeiwen.com/subject/bbyniftx.html