题目
解题思路
法一:暴力回溯
看到题目给的示意图(一个迷宫),首先想到的就是回溯法,使用一个变量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 ight)),到达该格可能的路径条数(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}= binom{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;
}
};