64. Minimum Path Sum

来源:互联网 发布:哈工大威海 知乎 编辑:程序博客网 时间:2024/06/05 19:53

Given a m x n grid filled with non-negative numbers, find a path from top left to bottom right which minimizes the sum of all numbers along its path.

Note: You can only move either down or right at any point in time.

最初做这道题没有想到动态规划,其实这是一道典型的冬天规划题目,后来我想利用递归解决也没有写出合理的代码,真是菜鸟一枚,使用动态规划求解问题,最重要的就是确定动态规划三要素:问题的阶段、每个阶段的状态以及从前一个阶段转化到后一个阶段之间的递推关系,递推关系必须是从次小的问题开始到较大的问题之间的转化,从这个角度来说,动态规划往往可以用递归程序来实现,不过因为递推可以充分利用前面保存的子问题的解来减少重复计算,所以对于大规模问题来说,有递归不可比拟的优势,这也是动态规划算法的核心之处,动态规划的整个求解过程可以用一个决策表来描述,最优决策表是一个二维表,其中行表示决策的阶段,列表示问题的状态,表格需要填写的数据一般对应此问题在某个阶段某个状态下的最优值(如最短路径、最长公共子序列、最大价值等),填表的过程就是根据递推关系,从1行1列开始,以行或者列优先的顺序,依次填写表格,最后根据整个表格的数据求得问题的最优解,代码如下:

public int minPathSum(int[][] grid) {
        // 特殊情况处理
        if(grid == null || grid.length == 0){
            return 0;
        }
        
        int[][] result = new int[grid.length][grid[0].length];
        // 对于第一行和第一列的数据需要进行单独处理
        result[0][0] = grid[0][0];
        for(int i = 1; i < grid.length; i++){
            result[i][0] = result[i - 1][0] + grid[i][0];
        }
        for(int j = 1; j < grid[0].length; j++){
            result[0][j] = result[0][j - 1] + grid[0][j];
        }
        
        for(int i = 1; i < grid.length; i++){
            for(int j = 1; j < grid[0].length; j++){
                result[i][j] = grid[i][j] + Math.min(result[i - 1][j], result[i][j - 1]); 
            }
        }
        
        return result[grid.length - 1][grid[0].length - 1];
    }

递归方式解决方案如下:


public int getMin(int i, int j){
        if(i == 0 && j == 0){
            return grid[0][0];
        }
        if(i == -1 || j == -1){
            return Integer.MAX_VALUE;
        }
        return Math.min(getMin(i - 1, j), getMin(i, j - 1)) + grid[i][j];
    }

递归方式中问题的规模是逐渐变小,在计算过程中存在相同问题重复计算的操作,因此会超时而不适合我们本题的解决方案,在该题中,我们可以将空间复杂度降到0,代码如下:

public int minPathSum(int[][] grid) {
      // 特殊情况处理
      if(grid == null || grid.length == 0){
          return 0;
      }
      int m = grid.length; 
      int n = grid[0].length;
      for(int i = 0; i < m; i++){
          for(int j = 0; j < n; j++){
              if(i == 0 && j == 0){
                  grid[i][j] = grid[i][j];
              }else if(i == 0 && j != 0){
                  grid[i][j] = grid[i][j] + grid[i][j - 1];
              }else if(j == 0 && i != 0){
                  grid[i][j] = grid[i - 1][j] + grid[i][j];
              }else{
                  grid[i][j] = grid[i][j] + Math.min(grid[i - 1][j], grid[i][j - 1]);
              }
          }
      }
      
      return grid[m - 1][n - 1];
    }

思路是一样的,不同的是我们在原来的数组上面进行了操作



0 0