[Leetcode] 62. 不同路径 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
Acceml

[Leetcode] 62. 不同路径

  •  
  •   Acceml
    Acceml 2018 年 9 月 7 日 1858 次点击
    这是一个创建于 2786 天前的主题,其中的信息可能已经有所发展或是发生改变。

    题目

    一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“ Start ” )。

    机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“ Finish ”)。

    问总共有多少条不同的路径?

    image.png

    例如,上图是一个 7 x 3 的网格。有多少可能的路径?

    说明:m 和 n 的值均不超过 100。

    示例 1:

    输入: m = 3, n = 2 输出: 3 解释: 从左上角开始,总共有 3 条路径可以到达右下角。 1. 向右 -> 向右 -> 向下 2. 向右 -> 向下 -> 向右 3. 向下 -> 向右 -> 向右 

    示例 2:

    输入: m = 7, n = 3 输出: 28 

    题解

    这道题拿到题目我觉得大家的第一反应都是这应该是递归的题目,因为我们可以转化为子问题,但是这样暴力肯定会超时,就不用尝试了。其实在该题递归的方法就是从上面到下面不断的去尝试,如果我们能记住之前的结果,就对我们下一步有帮助,所以想到了 DP 的方法。 格子中的数字代表当前的方法.

    1. 初始状态

    1.png

    1. 当前这个状态只和左边和上边的格子有关系.

    2.png

    1. 依次求解

    3.png

    于是我们可以得到状态转移方程:

    ways[i][j] = ways[i-1][j + ways[i][j-1]; 

    java 代码

    public class Solution { public int uniquePaths(int m, int n) { int[][] ways = new int[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if (i == 0 || j == 0) ways[i][j] = 1; else ways[i][j] = ways[i-1][j] + ways[i][j-1]; } } return ways[m-1][n-1]; } } 

    优化

    上面图 3 我们在求解的时候,我们是一行一行求解的,实际上我们只需要记录遍历到(i, j)这个位置的时候当前行有几种路径,如果遍历到(i, m-1)的时候,替换掉这一行对应列的路径即可,于是状态转移方程编程: res[j] = res[j] + res[j-1]

    class Solution { public int uniquePaths(int m, int n) { if (m <= 0 || n <= 0) { return 0; } int[] res = new int[n]; res[0] = 1; for (int i = 0; i < m; i++) { for (int j = 1; j < n; j++) { res[j] += res[j - 1]; System.out.println("i=" + i + "_" + "j=" + j + ":" + Arrays.toString(res)); } } return res[n - 1]; } } 

    有的同学可能还是不理解,我在代码里面打印了一些信息方便理解:

    i=0_j=1:[1, 1, 0, 0, 0, 0, 0] i=0_j=2:[1, 1, 1, 0, 0, 0, 0] i=0_j=3:[1, 1, 1, 1, 0, 0, 0] i=0_j=4:[1, 1, 1, 1, 1, 0, 0] i=0_j=5:[1, 1, 1, 1, 1, 1, 0] i=0_j=6:[1, 1, 1, 1, 1, 1, 1] //只记录到这一行的信息 i=1_j=1:[1, 2, 1, 1, 1, 1, 1] i=1_j=2:[1, 2, 3, 1, 1, 1, 1] i=1_j=3:[1, 2, 3, 4, 1, 1, 1] i=1_j=4:[1, 2, 3, 4, 5, 1, 1] i=1_j=5:[1, 2, 3, 4, 5, 6, 1] i=1_j=6:[1, 2, 3, 4, 5, 6, 7] //只记录到这一行的信息 i=2_j=1:[1, 3, 3, 4, 5, 6, 7] i=2_j=2:[1, 3, 6, 4, 5, 6, 7] i=2_j=3:[1, 3, 6, 10, 5, 6, 7] i=2_j=4:[1, 3, 6, 10, 15, 6, 7] i=2_j=5:[1, 3, 6, 10, 15, 21, 7] i=2_j=6:[1, 3, 6, 10, 15, 21, 28] //只记录到这一行的信息 i=3_j=1:[1, 4, 6, 10, 15, 21, 28] i=3_j=2:[1, 4, 10, 10, 15, 21, 28] i=3_j=3:[1, 4, 10, 20, 15, 21, 28] i=3_j=4:[1, 4, 10, 20, 35, 21, 28] i=3_j=5:[1, 4, 10, 20, 35, 56, 28] i=3_j=6:[1, 4, 10, 20, 35, 56, 84] //只记录到这一行的信息 

    Math

    这个题其实可以用排列组合的方式来做。这其实是最开始想到的方法。 以模拟的[4, 7]的例子,每一条路径:

    1. 向右的肯定有 6 步;
    2. 向左的肯定有 3 步; 问题即为:c(9,3) = (9 * 8 * 7) / (1 * 2 * 3) = 84

    组合数公式:c(m,n) = m! / (n! * (m - n)!)

    java 代码

    java 直接套用公式会越界,下面结果我用 long 存储:

    1!=1 2!=2 3!=6 4!=24 5!=120 6!=720 7!=5040 8!=40320 9!=362880 10!=3628800 11!=39916800 12!=479001600 13!=6227020800 14!=87178291200 15!=1307674368000 16!=20922789888000 17!=355687428096000 18!=6402373705728000 19!=121645100408832000 20!=2432902008176640000 21!=-4249290049419214848 22!=-1250660718674968576 23!=8128291617894825984 24!=-7835185981329244160 

    需要稍微化简一下,化简的过程就是我求解 c(9,3)的第二步骤。

    class Solution { public int uniquePaths(int m, int n) { double dom = 1; double dedom = 1; int small = m < n ? m - 1 : n - 1; int big = m < n ? n - 1 : m - 1; for (int i = 1; i <= small; i++) { dedom *= i; dom *= small + big + 1 - i; } return (int) (dom / dedom); } } 

    python 代码

    python 代码就比较凶残了,一行代码搞定:

    class Solution: def uniquePaths(self, m, n): return int(math.factorial(m + n - 2) / math.factorial(m -1) / math.factorial(n-1)) 

    贴一下 DP 版本的代码

    class Solution: def uniquePaths(self, m, n): """ :type m: int :type n: int :rtype: int """ if m <= 0 or n <= 0: return 0 res = [0 for _ in range(0, n)] res[0] = 1 for i in range(0, m): for j in range(1, n): res[j] += res[j-1] return res[n-1] 

    热门阅读

    2 条回复    2018-09-08 08:40:07 +08:00
    baojiweicn2
        1
    baojiweicn2  
       2018 年 9 月 8 日 via iPhone
    高中数学题....口算都行....
    qwertyegg
        2
    qwertyegg  
       2018 年 9 月 8 日
    这个题目哪里要用到 DP,你从起点到终点,一共需要往右走 6 步,往下走 2 步。所有的组合可能是
    C(8,2) = 28
    关于     帮助文档     自助推广系统       API     FAQ     Solana     1539 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 41ms UTC 16:49 PVG 00:49 LAX 09:49 JFK 12:49
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86