【LeetCode】剑指DP:62. Unique Paths 寻找路径

一、概述

输入m、n两个整数,形成一个m*n的阵列,从左上角座标为(1,1)走到右下角座标为(m,n)的格子。输出不同的路径数。

这么说吧,能做出来的都是击败100%。

我唯一要吐槽的就是它题目中说m<100,n<100,然后我就用m=100和n=100测试是否溢出和是否TLE了。结果在testcase中根本没这个。坑死我了。

二、分析

1、数学方法

最开始我用DFS,m,n为十几的时候就开始TLE。

然后反应过来是组合数,就是m+n-2个选n-1个。问题来了,这组合数要用到阶乘,阶乘的增长速度是要比指数还要高的,如何避免溢出呢?先算分子再算分母再除的方法肯定是不行了,必定溢出。那怎么办?

我们有如下定理:

C_{m}^{n}=\frac{m!}{(m-n)!n!}=\frac{m*(m-1)*(m-2)*...*(m-n+1)}{n*(n-1)*(n-2)*...*1}

那么我们一定有\frac{m-n+1}{1}是整数,\frac{(m-n+1)*(m-n+2)}{1*2}是整数,第一个不用证明,第二个分子肯定是奇数乘偶数,那么除以二一定是整数,之后我们不会证明,但只要知道,递推下去每个分数都能整除,那么就是乘一个除一个乘一个除一个,不会溢出。代码如下:

class Solution {
public:
    int uniquePaths(int m, int n) {
        if(m <=0 || n <= 0) return 0;
        long long res = 1;
        for(int i = n; i < m+n-1 ; i++){
            res = res * i / (i- n + 1);
        }
        return (int)res;
    }
};

2、DP

既然可以用DP做,那么就一定有递推公式咯。我们来看一下:

假设从(1,1)到(i,j)共有k条路径,那么我们可以知道什么?

首先,到(i,j+1)至少有k条路径,这k条是由(i,j)得到的,(i,j)右移一个就得到了该路径。既然是至少,那就还有另外的路径:到(i,j+1),还可以通过(i,j-1)下移一个得到。所以说,

DP[i][j]=DP[i-1][j]+DP[i][j-1]

这就是递推公式。代码如下:

class Solution {
public:
    int uniquePaths(int m, int n) {
        vector<vector<int>> DP(m, vector<int>(n, 1));
        for(int i=1;i<m;i++)
            for(int j=1;j<n;j++)
                DP[i][j]=DP[i-1][j]+DP[i][j-1];
        return DP[m-1][n-1];
    }
};

三、总结

组合数的方法还是很容易看出来的。但是求出组合数就需要一定的技巧。DP我没看出来,这是与字符串处理不相同的一类DP问题。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章