62不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。
问总共有多少条不同的路径?
例如,上图是一个7 x 3 的网格。有多少可能的路径?
示例 1:
输入: m = 3, n = 2
输出: 3
解释:
从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向右 -> 向下
2. 向右 -> 向下 -> 向右
3. 向下 -> 向右 -> 向右
示例 2:
输入: m = 7, n = 3
输出: 28
提示:
1 <= m, n <= 100
- 题目数据保证答案小于等于
2 * 10 ^ 9
思路
记 f ( i , j ) f(i,j) f(i,j)为到达 ( i , j ) (i, j) (i,j)位置的路径条数,那么如图所示
到达 ( i , j ) (i, j) (i,j)有两种方式要么从 ( i − 1 , j ) (i-1, j) (i−1,j)向右走一步得到,要么从 ( i , j − 1 ) (i, j-1) (i,j−1)往下走一步得到则到达 ( i , j ) (i, j) (i,j)路径条数为到 ( i − 1 , j ) (i-1, j) (i−1,j)与到 ( i , j − 1 ) (i, j-1) (i,j−1)之和。用数学递推式表示为:
递归
int uniquePaths(int m, int n) {
if (m < 1 || n < 1) return 0;
if (m == 1 || n == 1) return 1;
return uniquePaths(m -1, n) + uniquePaths(m, n -1);
}
带备忘录的递归
int uniquePaths(vector<vector<int>>& memo, int i, int j) {
if (i == 1 || j == 1) {
memo[i - 1][j - 1] = 1;
return 1;
}
if (memo[i - 2][j - 1] != 0 && memo[i - 1][j - 2] != 0) {
memo[i - 1][j - 1] = memo[i - 2][j - 1] + memo[i - 1][j - 2];
} else if (memo[i - 2][j - 1] == 0 && memo[i - 1][j - 2] != 0) {
memo[i - 1][j - 1] = uniquePaths(memo, i - 1, j) + memo[i - 1][j - 2];
} else if (memo[i - 2][j - 1] != 0 && memo[i - 1][j - 2] == 0) {
memo[i - 1][j - 1] = memo[i - 2][j - 1] + uniquePaths(memo, i, j - 1);
} else {
memo[i - 1][j - 1] = uniquePaths(memo, i - 1, j) + uniquePaths(memo, i, j - 1);
}
return memo[i - 1][j - 1];
}
int uniquePaths(int m, int n) {
if (m < 1 || n < 1) return 0;
vector<vector<int>> memo(m, vector<int>(n, 0)); // 备忘录 二维数组初值全为0
return uniquePaths(memo, m, n);
}
迭代
int uniquePaths(int m, int n) {
if (m < 1 || n < 1) return 0;
vector<vector<int>> memo(m, vector<int> (n, 0)); // 备忘录 二维数组初值全为0
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (i == 1 || j == 1) memo[i-1][j-1] = 1;
else memo[i-1][j-1] = memo[i-2][j-1] + memo[i-1][j-2];
}
}
return memo[m-1][n-1];
}
// 备忘录记录上一行的值
// 从上一行的值推出下一行的值
int uniquePaths(int m, int n) {
if (m < 1 || n < 1) return 0;
vector<int> preLine(m,1); // 上一行的值
vector<int> curLine(m,1); // 当前行的值
for (int i = 1; i < n; ++i) { // 逐行遍历
for (int j = 1; j < m; ++j){
curLine[j] = curLine[j-1] + preLine[j];
}
std::copy(curLine.begin(),curLine.end(),preLine.begin());
}
return preLine[m-1];
}
如图所示:可以只记录上一行的值;在上一行的基础上逐列修改成下一行的值
// 备忘录记录上一行的值
// 在上一行的基础上逐列修改
int uniquePaths(int m, int n) {
if (m < 1 || n < 1) return 0;
vector<int> curLine(m,1); // 当前行的值
for (int i = 1; i < n; ++i) { // 逐行遍历
for (int j = 1; j < m; ++j){
curLine[j] += curLine[j-1];
}
}
return curLine[m-1];
}