前言
递归是树结构或图结构的遍历搜索的基础算法,动态规划可以模拟问题的规律,让大问题变得更简单的同时,也减少很多不必要的计算。通过不同路径来夯实递归和动态规划。
一、案例
1、不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。
问总共有多少条不同的路径?
2、示例
二、题解
1、递归
通过递归来模拟有多少条路径,但是每条路径都要亲自模拟,所以很耗时。
A.带成员变量的递归
int res = 0;
int m, n;
//第一种递归,超时。
public int uniquePaths(int m, int n) {
this.m = m;
this.n = n;
recursion(0, 0);
return res;
}
private void recursion(int i, int j) {
if (i >= m || j >= n) return;
if (i == m - 1 && j == n - 1) {
res++;
return;
}
recursion(i + 1, j);
recursion(i, j + 1);
}
B.纯递归
//第二种递归,超时。
public int uniquePaths2(int m, int n) {
return recursion(0, 0, m, n);
}
private int recursion(int i, int j, int m, int n) {
if (i >= m || j >= n) return 0;
if (i == m - 1 && j == n - 1) {
return 1;
}
return recursion(i + 1, j, m, n) + recursion(i, j + 1, m, n);
}
二、动态规划
可以看出从第二行的第二个开始,每一个格子只能是从左边或者上边过来,所以达到每个格子的不同路径数就等于左边格子的数+上边格子的数。
1、初始化第一行第一列
//动态规划,初始化第一行第一列
public int uniquePaths3(int m, int n) {
int dp[][] = new int[m][n];
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int i = 0; i < n; i++) dp[0][i] = 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 - 1][n - 1];
}
2、不初始化
public int uniquePaths(int m, int n) {
int dp[][] = new int[m + 1][n + 1];
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];
}
总结
1)实在想不出来,带着自己的部分疑惑去看题解,不浪费太多宝贵的时间。
2)从递归算法到动态规划,学到了解算法题不仅仅是应用经典的算法模式,而是仔细观察问题中的更多细节和规律,利用起来从而降低时空复杂度。
参考文献
[1]LeetCode 原题