动态规划求解路径问题

动态规划求解的两个条件:

    1)最优解问题

    2)大问题可以拆分成小问题,大问题的最优解包含小问题的最优解,将小问题的最优解保存起来,在求大问题最优解的时候无需重新求解,直接拿来用即可。

具体问题

需求一:

    给定m*n矩阵,从左上角出发,到右下角,每次只能向右走或者向下走,求共有多少路径?

分析:

    假设路径数是f(m, n),那么第一步如果向右走,那么有f(m, n-1)种走法,如果第一步向下走,那么有f(m-1, n)种走法,所以可以得到递推式:f(m, n) = f(m, n-1) + f(m-1, n)。这样就可以使用DP求解。并且,如果m或n为1,即只有一行或者只有一列,那么共有一条路径。可以创建int[m+1][n+1]数组,给只有一行/一列的元素置1,然后递推求解。

代码:
class Solution {
    public int uniquePaths(int m, int n) {
        //第一步向右走或者向下走,如果向右走,就是f(m, n-1),向下走,还有f(m-1, n)种情况
        //所以f(m, n) = f(m, n-1)+f(m-1, n)
        //可以使用动态规划,设置二维数组
        int[][] dp = new int[m+1][n+1];
        
        //如果m==1或者n==1,那么就一种情况
        for(int i = 1; i <= m; i++)
            dp[i][1] = 1;
        for(int i = 1; i <= n; i++)
            dp[1][i] = 1;
        
        for(int i = 2; i <= m; i++){
            for(int j = 2; j <= n; j++)
                dp[i][j] = dp[i-1][j]+dp[i][j-1];
        }
        
        return dp[m][n];
    }
}
需求二:

    给定二维数组m*n,每个元素的值表示距离,求从[0][0]到[m-1][n-1]的最短距离,每次只能向右走或者向下走。

分析:

    动态规划的问题。我们可以正向求解,求出起点到每个点的最短距离,也可以反向求解,求出每个节点到终点的最短距离。

    1)正向求解

        对于第一个点,距离就是它的值。对于第一行的点,到起点的最短距离就是当前点的值加上左边点到起点的最短距离。对于第一列的点,到起点的最短距离就是当前点到上一个点到起点的最短距离。对于其它的点,要么是从上面的点过来,要么是从下面的点过来,所以求二者的最小值,加上当前点的值即可。最后返回终点到起点的距离即可。

    2)反向求解

        对于最后一个点,距离就是它的值。对于最后一行的点,到终点的最短距离就是当前值加上右边点到终点的最短距离。对于最后一列的点,到终点的距离就是当前值加上其下面一个点到终点最短距离。对于其它的点,要么是向右走,要么向下走,选择二者的较小值加上当前值即为最短距离。最后返回起点到终点的距离。

    3)原始数组是否可以改变?

        如果可以改变,那么可以直接在原始数组上进行修改,如果正向求解,那么修改后的数组中的值就是到起点的最短距离,如果是反向求解,那么修改后的数组中的值就是到终点的最短距离。

        如果不可以改变,那么需要创建和原始数组同大小的数组,正向求解和反向求解的结果同上。

代码:
class Solution {
    public int minPathSum(int[][] grid) {
        //异常处理
        if(grid == null || grid.length == 0)
            return 0;

        //思路一:修改数组grid,正向求解
        for(int i = 0; i < grid.length; i++){
            for(int j = 0; j < grid[0].length; j++){
                if(i == 0 && j == 0)
                    grid[i][j] = grid[i][j];
                else if(i == 0 && j != 0)
                    grid[i][j] += grid[i][j-1];
                else if(i != 0 && j == 0)
                    grid[i][j] += grid[i-1][j];
                else
                    grid[i][j] += Math.min(grid[i-1][j], grid[i][j-1]);
            }
        }
        
        return grid[grid.length-1][grid[0].length-1];
        
        /*
        //思路二:修改数组,反向求解 
        for(int i = grid.length-1; i >= 0 ; i--){
            for(int j = grid[0].length-1; j >= 0; j--){
                if(i == grid.length-1 && j == grid[0].length-1)
                    grid[i][j] = grid[i][j];
                else if(i != grid.length-1 && j == grid[0].length-1)
                    grid[i][j] += grid[i+1][j];
                else if(i == grid.length-1 && j != grid[0].length-1)
                    grid[i][j] += grid[i][j+1];
                else
                    grid[i][j] += Math.min(grid[i+1][j], grid[i][j+1]);
            }
        }
        
        return grid[0][0];
        */

        /*
        //思路三:开辟新的数组,正向求解
        int row = grid.length, col = grid[0].length;
        
        int[][] dp = new int[row][col];
        
        for(int i = row-1; i >= 0; i--){
            for(int j = col-1; j >= 0; j--){
                if(i == row-1 && j == col-1)
                    dp[i][j] = grid[i][j];//表示最后一个元素到最后一个元素的最短距离
                else if(i == row-1 && j != col-1)
                    dp[i][j] = grid[i][j] + dp[i][j+1];
                else if(i != row-1 && j == col-1)
                    dp[i][j] = grid[i][j] + dp[i+1][j];
                else
                    dp[i][j] = grid[i][j] + Math.min(dp[i+1][j], dp[i][j+1]);
            }
        }
        
        return dp[0][0];
        */
        
        /*
        //思路四:开辟新的数组,正向求解
        int row = grid.length, col = grid[0].length;
        
        int[][] dp = new int[row][col];
        for(int i = 0; i < row; i++){
            for(int j = 0; j < col; j++){
                if(i == 0 && j == 0)
                    dp[i][j] = grid[i][j];
                else if(i == 0 && j != 0)
                    dp[i][j] = grid[i][j]+dp[i][j-1];
                else if(i != 0 && j == 0)
                    dp[i][j] = grid[i][j]+dp[i-1][j];
                else
                    dp[i][j] = grid[i][j]+Math.min(dp[i-1][j], dp[i][j-1]);
            }
        }
        
        return dp[row-1][col-1];
        */

    }
}

你可能感兴趣的:(动态规划,Java基础,算法)