这一题有多种解决方法,下面介绍我使用到的两种方法:
- 排列组合方法
- 动态规划
方法1:排列组合
- 首先看这个示例,m=3表示行,n=7表示列;
- 然后不难想到,想要到达右下角,机器人的行动路径中,必然有且只有2步向下移动,有且只有6步向右移动,机器人到达右下角必然需要移动8步。
- 最后,我们就可以通过排列组合的方法计算路径数量了,机器人要移动8步,在这8步中有2步是向下移动,有6步是向右移动。从8步中任选2步向下移动,使用组合公式:
由上述实例对应到一般情况:
- 已知m和n,可以得到,机器人向下移动的步数为 (m-1) ,向右移动的步数为 (n-1) ,移动的总步数为 (m-1+n-1)=(m+n-2) 。
- 得到一般情况的组合公式:
由上述一般情况的公式,就可以直接计算出任意m和n对应的路径数
python的math库中提供了计算阶乘的factorial()函数。
(不清楚C++的阶乘函数,这里只用了python解答,不过自己写一个阶乘函数也很简单)
下面是使用python的解答:
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
"""排列组合方法"""
return int(math.factorial(m+n-2)/(math.factorial(m-1)*math.factorial(n-1)))
方法2:动态规划
我们还是使用上面那个示例来介绍。
- 对于m×n的网格,我们可以构造一个m×n的矩阵,矩阵中每个元素的值,代表机器人从起始点到这个元素所在位置的路径数。(先令每个元素为0)
0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 0 |
- 对于第一行的每个元素,机器人只有一条路径能够到达,即一直向右移动;对于第一列的元素,机器人同样只有一条路径能够到达,即一直向下移动。因此,可以将第一行和第一列的元素赋值为1.(这里就是动态规划的初始条件)
1 | 1 | 1 | 1 | 1 | 1 | 1 |
1 | 0 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 |
- 对于其他位置的元素,我们可以知道,到达这个元素的路径只有两种,就是从这个元素上方向下移动,或者从这个元素的左侧向右移动。所以可以知道,到达这个元素的路径数就等于这个元素左侧元素的值加这个元素上方元素的值。(这就是动态规划的递推式)
1 | 1 | 1 | 1 | 1 | 1 | 1 |
1 | 2 | 0 | 0 | 0 | 0 | 0 |
1 | 0 | 0 | 0 | 0 | 0 | 0 |
- 因此可以计算出所有元素的值
1 | 1 | 1 | 1 | 1 | 1 | 1 |
1 | 2 | 3 | 4 | 5 | 6 | 7 |
1 | 3 | 6 | 10 | 15 | 21 | 28 |
- 此时,矩阵的最后一个元素的值就表示从初始点到达终点的路径总数,即28。
下面是使用Python的解答:
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
"""动态规划求解不同路径"""
# 创建一个m×n的矩阵,每个元素都为0
N = [0 for _ in range(n)] # 创建长度为n的列表,每个元素都为0
M = [N for _ in range(m)] # 创建长度为m的列表,每个元素都为列表n
for i in range(n):
M[0][i] = 1 # 将矩阵第一行元素赋值为1
for i in range(m):
M[i][0] = 1 # 将矩阵第一列元素赋值为1
for i in range(1, m):
for j in range(1, n):
# 除去第一行和第一列的每个元素的值,都等于其左侧和正上方值的和
M[i][j] = M[i][j-1] + M[i-1][j]
return M[-1][-1] # 返回最后一列最后一行元素,即总共的路径数
下面是使用C++的解答:
class Solution {
public:
int uniquePaths(int m, int n) {
vector<int> N(n, 0);
vector<vector<int>> M(m, N);
for(int i=0; i<N.size();i++){
M[0][i] = 1;
}
for(int i=0; i<M.size();i++){
M[i][0] = 1;
}
for(int i=1; i<M.size();i++){
for(int j=1; j<N.size();j++){
M[i][j] = M[i][j-1] + M[i-1][j];
}
}
return M.back().back();
}
};