Medium
题目描述
一个机器人位于一个 m x n 网格的左上角(起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
示例 1:
输入:m = 3, n = 7
输出:28
示例 2:
输入:m = 3, n = 2
输出:3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 右 -> 下 -> 下
2. 下 -> 下 -> 右
3. 下 -> 右 -> 下
提示:
- 1 <= m, n <= 100
- 题目数据保证答案小于等于 2 * 10^9
解题思路
解题思路
这是一道经典的动态规划问题,也可以用数学组合的方法解决。
方法一:动态规划
核心思想: 到达每个位置的路径数等于到达其上方位置和左方位置的路径数之和。
状态定义: dp[i][j] 表示到达位置 (i,j) 的不同路径数。
状态转移: dp[i][j] = dp[i-1][j] + dp[i][j-1]
边界条件: 第一行和第一列的所有位置都只有一条路径可以到达。
空间优化: 由于每次只需要用到上一行的数据,可以用一维数组优化空间复杂度。
方法二:数学组合(推荐)
核心思想: 从左上角到右下角,总共需要向右走 n-1 步,向下走 m-1 步,总共 m+n-2 步。问题转化为:在 m+n-2 个位置中选择 m-1 个位置向下走(或选择 n-1 个位置向右走)的组合数。
公式: C(m+n-2, m-1) = (m+n-2)! / ((m-1)! × (n-1)!)
为避免大数计算,可以使用递推公式计算组合数。
代码实现
class Solution {
public:
int uniquePaths(int m, int n) {
// 数学组合方法
long long ans = 1;
for (int i = 1; i <= min(m - 1, n - 1); i++) {
ans = ans * (m + n - 1 - i) / i;
}
return ans;
}
};
class Solution:
def uniquePaths(self, m: int, n: int) -> int:
# 数学组合方法
from math import comb
return comb(m + n - 2, m - 1)
public class Solution {
public int UniquePaths(int m, int n) {
// 数学组合方法
long ans = 1;
for (int i = 1; i <= Math.Min(m - 1, n - 1); i++) {
ans = ans * (m + n - 1 - i) / i;
}
return (int)ans;
}
}
var uniquePaths = function(m, n) {
// 数学组合方法
let ans = 1;
for (let i = 1; i <= Math.min(m - 1, n - 1); i++) {
ans = ans * (m + n - 1 - i) / i;
}
return ans;
};
复杂度分析
| 方法 | 时间复杂度 | 空间复杂度 |
|---|---|---|
| 动态规划(二维) | O(m × n) | O(m × n) |
| 动态规划(一维优化) | O(m × n) | O(n) |
| 数学组合 | O(min(m, n)) | O(1) |
相关题目
. Unique Paths II (Medium)
. Minimum Path Sum (Medium)
. Dungeon Game (Hard)
. Minimum Path Cost in a Grid (Medium)
. Number of Ways to Reach a Position After Exactly k Steps (Medium)