1. 程式人生 > 其它 >leetcode 62. 不同路徑 (回溯 動態規劃 排列組合 )

leetcode 62. 不同路徑 (回溯 動態規劃 排列組合 )

連結:https://leetcode-cn.com/problems/unique-paths/

題目

一個機器人位於一個 m x n網格的左上角 (起始點在下圖中標記為 “Start” )。

機器人每次只能向下或者向右移動一步。機器人試圖達到網格的右下角(在下圖中標記為 “Finish” )。

問總共有多少條不同的路徑?

示例

示例 1:

輸入:m = 3, n = 7
輸出:28
示例 2:

輸入:m = 3, n = 2
輸出:3
解釋:
從左上角開始,總共有 3 條路徑可以到達右下角。

  1. 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右
  3. 向下 -> 向右 -> 向下

示例 3:
輸入:m = 7, n = 3
輸出:28

示例 4:
輸入:m = 3, n = 3
輸出:6

提示:

1 <= m, n <= 100
題目資料保證答案小於等於 2 * 109

思路

看到路徑問題 最容易想到就是暴力搜尋路徑
因此可以簡化為遍歷搜尋二叉樹位元組點數量問題 用dfs 遞迴遍歷做

class Solution {
public:
    int uniquePaths(int m, int n) {
        return findpath(m,n,1,1);
    }
    int findpath(int m,int n,int x,int y)
    {
        if(x==m&&y==n)
            return 1;
        if(x+1<=m&&y+1<=n)
        {
            return findpath(m,n,x+1,y)+findpath(m,n,x,y+1);
        }
        return x==m? findpath(m,n,x,y+1):findpath(m,n,x+1,y);
    }
};

但是由於遞迴遍歷是指數級的時間複雜度,因此超時

轉換個思路,這其實是一道簡單的動態規劃題,問題可分解為求從起點到每一點的最大路徑量
由於移動過程中只能向下或者向左移動,因此到達棋盤中某位置[i,j]的路徑數為[i-1,j]位置和[i,j-1]位置的路徑和(在棋盤邊緣位置的路徑數預設初始化為1)
遍歷棋盤 更新dp陣列

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

實際上,本題是個排列組合問題,
起點到達終點的步數恆為m+n-2,問題轉化為組合問題從m+n-2個移動中取m-1種組合
根據公式

class Solution {
public:
    int uniquePaths(int m, int n) {
        long long ans=1;
        for(int i=1,j=n;i<m;i++,j++)
        {
            ans=ans*j/i;
        }
        return ans;
    }
};
分子m+n-2 -> n-1累乘
分母1 ->m-1 累乘

注意:

  1. 排列組合中階乘計算不能直接計算 會出現溢位 需要同時進行乘和除操作
  2. 資料型別使用long long