L64. 最小路径和

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

说明:每次只能向下或者向右移动一步。

示例:

输入:
[
[1,3,1],
[1,5,1],
[4,2,1]
]
输出: 7
解释: 因为路径 1→3→1→1→1 的总和最小。

1.暴力递推法
从上到右下递推

class Solution {
    public int minPathSum(int[][] grid) {
        
        //需要多加几个参数
        return find(grid, 0, 0);
    }
    int find(int[][] grid, int i, int j){
        //如果超出边界
        if(i == grid.length || j == grid[0].length) return Integer.MAX_VALUE;//递推边界
        if(i == grid.length - 1 && j == grid[0].length - 1) return grid[i][j];//到达正确的位置
        return grid[i][j] + Math.min(find(grid, i + 1, j), find(grid, i, j + 1));
    }
}

由下至上

class Solution {
    public int minPathSum(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        //需要多加几个参数
        return find(grid, m - 1, n - 1);
    }
    int find(int[][] grid, int i, int j){
        //如果超出边界
        if(i < 0 || j < 0)return Integer.MAX_VALUE;
        if(i == 0 && j == 0)return grid[i][j];
        return grid[i][j] + Math.min(find(grid, i - 1, j), find(grid, i, j - 1));
    }
}

2.动态规划,二维数组

class Solution {
    public int minPathSum(int[][] grid) {
        //由下至上
        int m = grid.length, n = grid[0].length;
        int dp[][] = new int[m][n];
        //dp[m - 1][n - 1] = grid[m - 1][n - 1];可以放在循环里赋值
        for(int i = m - 1; i >= 0; i--){
            for(int j = n - 1; j >= 0; j--){//分类讨论满足了从特殊到一般的if判断
                if(i == m - 1 && j == n - 1) dp[i][j] = grid[i][j];
                else if(i == m - 1) dp[i][j] = dp[i][j + 1] + grid[i][j];
                else if(j == n - 1) dp[i][j] = dp[i + 1][j] + grid[i][j];
                else dp[i][j] = Math.min(dp[i + 1][j], dp[i][j + 1]) + grid[i][j];
            }
        }
        return dp[0][0];
    }
}

甚至可以分开写

class Solution {
    public int minPathSum(int[][] grid) {
        //由下至上
        int m = grid.length, n = grid[0].length;
        int dp[][] = new int[m][n];
        dp[m - 1][n - 1] = grid[m - 1][n - 1];
        for(int i = m - 2; i >= 0; i--) dp[i][n - 1] = dp[i + 1][n - 1] + grid[i][n - 1];//先处理好边界
        for(int j = n - 2; j >= 0; j--) dp[m - 1][j] = dp[m - 1][j + 1] + grid[m - 1][j];
        for(int i = m - 2; i >= 0; i--) {
            for (int j = n - 2; j >= 0; j--) {
                dp[i][j] = Math.min(dp[i + 1][j], dp[i][j + 1]) + grid[i][j];
            }
        }
        
        return dp[0][0];
    }
}

3.从上到下

class Solution {
    public int minPathSum(int[][] grid) {
        //由下至上
        int m = grid.length, n = grid[0].length;
        int dp[][] = new int[m][n];
        
        for(int i = 0; i < m ; i++){
            for(int j = 0; j < n; j++){
                if(i == 0 && j == 0) dp[i][j] = grid[i][j];
                else if(i == 0) dp[i][j] = grid[i][j] + dp[i][j - 1];
                else if(j == 0) dp[i][j] = grid[i][j] +dp[i - 1][j];
                else dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1]) + grid[i][j];
            }
        }
        return dp[m - 1][n - 1];
        
    }
}

4.压缩至一维dp
从上到下判断:

class Solution {
    public int minPathSum(int[][] grid) {
        int m = grid.length, n = grid[0].length;
        int dp[] = new int[n];

        for(int i = 0; i < m; i++){
            for(int j = 0; j < n; j++){
                if(i == 0 && j == 0) dp[j] = grid[i][j];
                else if(i == 0) dp[j] = dp[j - 1] + grid[i][j];
                else if(j == 0) dp[j] = dp[j] + grid[i][j];
                else dp[j] = Math.min(dp[j], dp[j - 1]) + grid[i][j];
            }
        }
        return dp[n - 1];
    }
}

从下到上

class Solution {
    public int minPathSum(int[][] grid) {
        //由下至上
        //
        int m = grid.length, n = grid[0].length;

        int dp[] = new int[n];//变换为一维数组,每一行遍历的时候存储上一行
        //每一次数据更新的时候一般是需要其其下方的和其右边的数据,只要保证这些已经被更新即可
       for(int i = m - 1; i >= 0; i--){
           for(int j = n - 1; j >= 0; j--){
               if(i == m - 1 && j == n - 1) dp[j] = grid[i][j];
               else if(i == m - 1) dp[j] = dp[j + 1] + grid[i][j];
               else if(j == n - 1) dp[j] = dp[j] + grid[i][j];//不同之处,dp[j]是每一行开始循环的时候第一个更新的
               else dp[j] = Math.min(dp[j + 1], dp[j]) + grid[i][j];

           }
       }
       return dp[0];

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值