一、概述
輸入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問題。