LeetCode 64. Minimum Path Sum -备忘录法

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.

Example 1:
[[1,3,1],
[1,5,1],
[4,2,1]]

Given the above grid map, return 7. Because the path 1→3→1→1→1 minimizes the sum.

一眼看出这是一个用递归能解决的题,只要遍历一次所有的路径,找到路径的最小值便可。而题目规定只能往下或者往右,终结条件也给出了是右下角的那个数字,当前的解依赖于下一个元素(或右,或下)的最优解,只需要把子问题层层递推下去便可。子问题便是下一个元素为起点的所有路径中最短的那条。将每个元素为起点的当前最优路径看成一个状态,那么状态转移方程式建立如下:
从当前元素开始最短路径=当前元素值+从左边元素开始的最短路径与从下边开始元素最短路径之间最短的。
未优化代码:

class Solution {
    public static int minPathSum(int[][] grid) {
            /*
             * 遍历所有路线,记录最短的
             * 规则只能向右或者向下移动,所以需要判断碰到右边界或者上边界的情况
             * 如果遇到右边界只能往下,如果遇到下边界只能往右走,直到遇到右边界下边界的地方,即右下角终结点
             */

         return minSum(grid,0,0);
        }

     public static int minSum(int[][] grid,int down,int right) {

        int m=grid.length-1;//行数
        int n=grid[0].length-1;//列数

        if(down==m&&right<n)//下边界
            return grid[down][right]+minSum(grid,down,right+1);
        if(down<m&&right==n)
            return grid[down][right]+minSum(grid,down+1,right);
        if(down==m&&right==n)
            return grid[m][n];
          int sum1=grid[down][right]+minSum(grid,down+1,right);
          int sum2=grid[down][right]+minSum(grid,down,right+1);
        if(sum1>sum2)
         return sum2;
        else
            return sum1;
        }
}

这个代码在LeetCode上是过不了的,耗时太长
这里写图片描述
下面进行下优化,这个问题中很明显的一点就是对重复子问题求解了很多次,所以耗时是指数级的,如何重叠子问题的?那便是使用备忘录方法,利用空间换取时间效率,我们开辟一个数组,将已经计算过的子问题,存储下来,下次遇到直接用就行了。

    public static int minPathSum(int[][] grid) {
        /*
         * 遍历所有路线,记录最短的 规则只能向右或者向下移动,所以需要判断碰到右边界或者上边界的情况
         * 如果遇到右边界只能往下,如果遇到下边界只能往右走,直到遇到右边界下边界的地方,即右下角终结点
         */

        int flag[][] = new int[300][300]; // 开辟数组记录已计算值,300足以应付此题数据。
        return minSum(grid, 0, 0, flag);
    }

    public static int minSum(int[][] grid, int down, int right, int[][] flag) {

        int m = grid.length - 1;// 行数
        int n = grid[0].length - 1;// 列数
        if (flag[down][right] == 0) { // 如果记录数组中没有值。执行计算。如果有值直接拿出来

            if (down == m && right < n)// 下边界
            {
                flag[down][right] = grid[down][right] + minSum(grid, down, right + 1, flag); // 往右
                return flag[down][right];
            }
            if (down < m && right == n) // 右边界
            {
                flag[down][right] = grid[down][right] + minSum(grid, down + 1, right, flag);// 往左
                return flag[down][right];
            }
            if (down == m && right == n)// 终点
                return grid[m][n];

            int sum1 = grid[down][right] + minSum(grid, down + 1, right, flag);
            int sum2 = grid[down][right] + minSum(grid, down, right + 1, flag);
            if (sum1 > sum2) {
                flag[down][right] = sum2;
                return sum2;
            } else {
                flag[down][right] = sum1;
                return sum1;
            }
        } else {
            return flag[down][right];
        }
    }

这个代码是可以顺利通过的,时间效率高。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值