一、概述
输入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个。问题来了,这组合数要用到阶乘,阶乘的增长速度是要比指数还要高的,如何避免溢出呢?先算分子再算分母再除的方法肯定是不行了,必定溢出。那怎么办?
我们有如下定理:
那么我们一定有是整数,是整数,第一个不用证明,第二个分子肯定是奇数乘偶数,那么除以二一定是整数,之后我们不会证明,但只要知道,递推下去每个分数都能整除,那么就是乘一个除一个乘一个除一个,不会溢出。代码如下:
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问题。