题目
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
输入:m = 3, n = 7
输出:28
解法一:递归
递归怎么写?如果没有看别人的代码,自己应该怎么分析呢?
题目规定从左上角,走到右下角,起点和终点都是确定的。
由于只能往下走,或者往右走,那么我们在递归的时候,m-1就是往下走,n-1就是往右走。
那么我们如何求得路径的条数呢?
其实可以这样想:凡是能到达终点,那么就可以算一条路径
代码:
//向上递归(自底向上)
public int uniquePaths(int m, int n) {
if (m < 0 || n < 0) {
return 0;
}
if (m == 1 && n == 1) {
return 1;
}
return uniquePaths(m - 1, n) + uniquePaths(m, n - 1);
}
// 递归:向上
public int uniquePaths2(int m, int n) {
if (m == 1 || n == 1) {
return 1;
}
return uniquePaths2(m - 1, n) + uniquePaths2(m, n - 1);
}
// 递归:向下
public int uniquePaths3(int m, int n, int i, int j) {
if (i >= m || j >= n) {
return 0;
}
if (i == m - 1 && j == n - 1) {
return 1;
}
return uniquePaths3(m, n, i + 1, j) + uniquePaths3(m, n, i, j + 1);
}
解法二:回溯
我们初始化一个二维数组(int型、boolean型都行,反正都会超时)
返回的条件:
- 超出范围
- 到达终点
所以我们要记得判断超出范围的情况,当然也可以在下一轮dfs之前,进行范围的判断,这样思路更清晰一点。
int count = 0;
public int uniquePaths(int m, int n) {
int[][] arr = new int[m][n];
DFS(arr, 0, 0);
return count;
}
public void DFS(int[][] arr, int row, int col) {
if (row == arr.length - 1 && col == arr[0].length - 1) {
count++;
return;
}
if (row < arr.length - 1) {
DFS(arr, row + 1, col);
}
if (col < arr[0].length - 1) {
DFS(arr, row, col + 1);
}
}
解法三:动态规划
这道题也算是经典的动态规划了
- 判断边界
- 确定状态转移方程
public int uniquePaths4(int m, int n) {
int[][] arr = new int[m][n];
for (int[] a : arr) {
Arrays.fill(a, 1);// 我省略了判断边界,边界都是1
}
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
arr[i][j] = arr[i - 1][j] + arr[i][j - 1];
}
}
return arr[m - 1][n - 1];
}
高端的组合数学方法我就不讲了,我不会,也不想假装懂了。