1. 程式人生 > 實用技巧 >2020-12-9 不同路徑

2020-12-9 不同路徑

題目


解題思路

法一:暴力回溯

看到題目給的示意圖(一個迷宮),首先想到的就是回溯法,使用一個變數count來記錄路徑的條數,一旦找到一條路徑count便加一,詳情看程式碼。

class Solution {
public:
    int uniquePaths(int m, int n) {
        int count = 0;
        int a = 1, b = 1;	// 初始位置為(1,1)
        findPathCount(count, a, b, m, n);
        return count;
    }

    void findPathCount(int &count, int a, int b, int m, int n){
        if (a > m || b > n)	// 超出迷宮的範圍便直接退出
            return ;
            
        if (a == m && b == n){	// 到達終點count加1
            count++;
            return ;
        }
		
        findPathCount(count, a+1, b, m, n);	// 往下走&往右走
        findPathCount(count, a, b+1, m, n);
    }
};

由於該方法時間複雜度過高,提交後未能通過。

法二:動態規劃

經分析,對於迷宮中除了上邊界與左邊界的任一格\(\left(i,j\right)\),到達該格可能的路徑條數\(dp[i][j]=dp[i-1][j]+dp[i][j-1]\) ,而從起點出發到達上邊界或左邊界的任意一格的路徑數量均能為1,因為機器人只能往下走或往右走。因此可使用動態規劃來解決該問題。詳情看程式碼。

class Solution {
public:
    int uniquePaths(int m, int n) {
        long long dp[m][n];
		
        for (int i = 0; i < m; i++)   dp[i][0] = 1;
        for (int i = 0; i < n; i++)   dp[0][i] = 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];
    }
};

時間複雜度:\(O(mn)\)
空間複雜度:\(O(mn)\)

法三:組合數學

從左上角到右下角的過程中,我們需要向右移動n-1次,向下移動m-1次,共移動m+n-2次。因此路徑的總數,就等於從m+n-2次移動中選擇m-1次向下移動的方案數,即組合數:

\[C_{m+n-2}^{m-1}=\tbinom{m+n-2}{m-1}=\frac{(m+n-2)(m+n-3)...n}{(m-1)!}=\frac{(m+n-2)!}{(m-1)!(n-1)!} \]

兩種解法:

  • 直接呼叫組合數的API;
  • 自己寫程式碼計算;
class Solution {
public:
    int uniquePaths(int m, int n) {
        long long ans = 1;
        for (int x = n, y = 1; y < m; ++x, ++y) {
            ans = ans * x / y;
        }
        return ans;
    }
};

提交結果