【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問題。

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