题目
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
例如,上图是一个7 x 3 的网格。有多少可能的路径?
说明:m 和 n 的值均不超过 100。
示例 1:
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
- 向右 -> 向右 -> 向下
- 向右 -> 向下 -> 向右
- 向下 -> 向右 -> 向右
示例 2:
输入: m = 7, n = 3
输出: 28
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/unique-paths。
代码及分析
方法一:动态规划法(二维)
该问题可以通过动态规划的方法进行求解,动态规划最主要的是将其动态转移方程写出来。
由于该机器人只能向下和向右移动,故可以知道,对于位置m,n处,可以到达的路径总数等于位置m,n-1处以及位置m-1,n处可以到达的路径数之和,定义dp[i][j]为位置i,j处可以到达的路径总数,则有dp[i][j] = dp[i-1][j]+dp[i][j-1].
初始条件:dp[0][1] = 1; 这里是为了计算dp[1][1]。
int uniquePaths(int m, int n) {
vector<vector<int>> dp(m,vector<int>(n+1,0));
dp[0][1] = 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][n];
}
复杂度:
时间复杂度: O(mn) 。
空间复杂度: O(mn) 。
方法二:动态规划法(一维)
对于动态规划问题一般二维的动态转移矩阵可以设法考虑是否可以转换为一维数组。
上述方法一中动态转移方程为dp[i][j] = dp[i-1][j]+dp[i][j-1],每一次循环中,i仅与i-1有关,故可以写成dp[j] += dp[j-1],这相当于对于每一层外循环,dp数组保存第i行对应的可以到达的路径总和。
int uniquePaths(int m, int n) {
vector<int> dp(n+1,0);
dp[1] = 1;
for(int i = 1; i <= m; i++)
{
for(int j =1; j <= n; j++)
{
dp[j] += dp[j-1];
}
}
return dp[n];
}
复杂度:
时间复杂度: O(mn) ;
空间复杂度: O(n) 。
方法三:组合数
这个问题中,机器人要到达矩阵的右下角,一共需要走m+n-2步,其中m-1步向下,n-1步向右,故这个问题可以看成是一个组合数的问题,即在m+n-2步中选取m-1步用于向下走,
C
m
+
n
−
2
m
−
1
=
(
m
+
n
−
2
)
!
(
m
−
1
)
!
(
n
−
1
)
!
\ C_{m + n-2}^{m-1}=\frac{(m+n-2)!}{(m-1)!(n-1)!}
Cm+n−2m−1=(m−1)!(n−1)!(m+n−2)!
由于
C
m
+
n
−
2
m
−
1
=
C
m
+
n
−
2
n
−
1
\ C_{m + n-2}^{m-1}=C_{m + n-2}^{n-1}
Cm+n−2m−1=Cm+n−2n−1,故在计算的过程中我们可以选择m,n中的较小值用于计算。
int uniquePaths(int m, int n) {
long res = 1;
int k = m < n ? m : n;
k = k - 1;
int t = m + n - 2;
for(int i = 1; i <= k; i++)
{
res = res * (t - k + i) / i;
}
return int(res);
}
需要注意的两点是:
1、在这里定义res时,不能定义为 int 型,因为在计算 res = res * (t - k + i) / i的过程中容易超过int的范围;
2、 res = res * (t - k + i) / i ; 这一步不可以写成 res * = (t - k + i) / i ;
例如:m=4, n = 4时,k = 3, t = 6,
i = 1 res * = (t - k + i) / i = 4; res = res * (t - k + i) / i = 4;
i = 2 res * = (t - k + i) / i = 8; res = res * (t - k + i) / i = 10;
i = 3 res * = (t - k + i) / i = 16; res = res * (t - k + i) / i = 20;
复杂度:
时间复杂度: O(k) ;
空间复杂度: O(1) 。