leetcode 62. 不同路徑 (回溯 動態規劃 排列組合 )
阿新 • • 發佈:2021-09-07
連結: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 條路徑可以到達右下角。
- 向右 -> 向下 -> 向下
- 向下 -> 向下 -> 向右
- 向下 -> 向右 -> 向下
示例 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 累乘
注意:
- 排列組合中階乘計算不能直接計算 會出現溢位 需要同時進行乘和除操作
- 資料型別使用long long