个人记录-LeetCode 62. Unique Paths

问题:
A robot is located at the top-left corner of a m x n grid (marked ‘Start’ in the diagram below).
The robot can only move either down or right at any point in time. The robot is trying to reach the bottom-right corner of the grid (marked ‘Finish’ in the diagram below).
How many possible unique paths are there?
这里写图片描述

Note: m and n will be at most 100.

代码示例:
1、分治
Robot每次都可以选择向下走一步,或者向右走一步。
因此每个位置的结果,都可以表示为:
从当前位置向下走一步的结果,与从当前位置向右走一步的结果之和。

这其实就是分治的思想,代码如下:

public class Solution {
    public int uniquePaths(int m, int n) {
        //m或n <= 0 时,结果为0
        if (m <= 0 || n <= 0) {
            return 0;
        }

        //m或n == 1时,只能一直向右,或者一直向下
        //于是只有1种走法
        if (m == 1 || n == 1) {
            return 1;
        }

        //向右走一步的结果,加上向下走一步的结果
        return uniquePaths(m, n-1) + uniquePaths(m-1, n);
    }
}

这种方法是可行的,但递归相当耗时,
因为其中会进行大量的重复计算。

我们以m、n都为3举例,递归过程如下图所示:

图中红色部分即为重复计算的地方。
显然m、n越大,重复计算的部分越大,越耗时。
在自己的电脑上试了一下,当m、n均为100时,耗时40min还没有搞定 。

2、动态划归
既然使用分治这种正面拆解的方法,不能有效解决问题,
那么我们可以逆向思考,用小结果拼凑出大结果,即动态划归的思想。

思路如下图所示:

从图中可以看出(看颜色标记的区域),每个位置都等于:
同一行前一列的结果,与同一列前一行结果的和。
这其实就是分治的逆过程。

不过我们可以记录每个位置的值,直接计算求得结果,省去重复计算的麻烦。

代码如下:

public class Solution {
    public int uniquePaths(int m, int n) {
        //(m+1)行,(n+1)列
        //第0行,第0列均置为0
        int[][] rst = new int[m+1][n+1];
        for (int j = 0; j < n+1; j++) {
            rst[0][j] = 0;
        }

        for (int i = 0; i < m+1; ++i) {
            rst[i][0] = 0;
        }

        //m、n均为1时,结果为1
        rst[1][1] = 1;
        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <=n; ++j) {
                //rst[i][j]初始为0
                //为了兼容i=1,j=1的场景,写成下列公式
                rst[i][j] = rst[i][j-1] + rst[i-1][j] + rst[i][j];
            }
        }

        //返回结果
        return rst[m][n];
    }
}

m、n均为100时(结果已经越界,需要将int替换为long),耗时1ms都不到。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值