62.不同路径
// 动态规划清晰步骤: 1. 定义dp数组 2. 初始化 3. 循环填充 4. 返回结果
class Solution {
// 也是一个从起点到终点的问题, 1) dp[i][j],表示i,j格子的不同路径数, 2) dp[0][0] = 1 dp[0][1] =1 dp[1][0] = 1 3) dp[i][j] = dp[i-1][j] + dp[i][j-1]; 4) 左上到右下
public int uniquePaths(int m, int n) {
// 1. 定义dp数组
int[][] dp = new int[m][n];
// 2. 初始化
for (int i = 0; i < m; i++) dp[i][0] = 1;
for (int j = 0; j < n; j++) dp[0][j] = 1;
// 3. 循环填充
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];
}
}
// 4. 返回结果
return dp[m - 1][n - 1];
}
}
// 动态规划写法2: 内部解决初始化问题
class Solution2 {
public int uniquePaths(int m, int n) {
int[][] dp = new int[m][n];
for (int i = 0; i < m; i++) {
for (int j = 0; j < n; j++) {
if (i == 0 && j != 0) {
dp[i][j] = dp[i][j - 1];
} else if (i != 0 && j == 0) {
dp[i][j] = dp[i - 1][j];
} else if (i == 0 && j == 0) {
dp[i][j] = 1;
} else {
dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
}
}
}
return dp[m - 1][n - 1];
}
}
// 深度优先搜索DFS: 可以遍历二叉树, 可以从头到尾遍历每一条路径(更彻底), 但是本题只需要知道多少条路径。所以是充分不必要条件。
// 所有寻路的过程可以连接成一个二叉树, 每个叶子节点说明一条路径
class Solution3 {
private int postOrder(int i, int j, int m, int n) {
//越界, 不能构成一种可能, 但是在这里也会发现即使不构成可能也会被算法遍历这种可能(产生过搜索),时间复杂度高
// Leetcode中会超时, 可以进行剪枝优化
if (i >= m || j >= n) return 0;
// 符合条件的一种可能
if (i == m - 1 && j == n - 1) return 1;
int left = postOrder(i + 1, j, m, n);
int right = postOrder(i, j + 1, m, n);
return left + right;
}
public int uniquePaths(int m, int n) {
return postOrder(0, 0, m, n);
}
}
// 剪枝, LeetCode中还是会超时
class Solution4 {
private int postOrder(int i, int j, int m, int n) {
// 符合条件的一种可能
if (i == m - 1 && j == n - 1) return 1;
int left = 0;
int right = 0;
if (i + 1 < m) left = postOrder(i + 1, j, m, n);
if (j + 1 < n) right = postOrder(i, j + 1, m, n);
return left + right;
}
public int uniquePaths(int m, int n) {
return postOrder(0, 0, m, n);
}
}
// 排列组合思路:我们需要移动 (m - 1) + (n - 1)次,其中有 m−1 次向下移动,n−1 次向右移动。因此路径的总数,就等于从 m+n−2 次移动中选择 m−1 次向下移动的方案数,即组合数:
// 计算是全排列然后去重
63. 不同路径 II
// 本题很简单, 只需要将62题, dp数组对于障碍物的位置改为0即可: 1. 定义dp数组 2. 初始化 3. 循环填充 4. 返回结果
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
// 1. 定义dp数组
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[][] dp = new int[m][n];
// 2. 初始化
if (obstacleGrid[0][0] == 1) return 0; // 打补丁测试用例
dp[0][0] = 1;
for (int i = 1; i < m; i++) if (obstacleGrid[i][0] == 0) dp[i][0] = dp[i - 1][0];
for (int j = 1; j < n; j++) if (obstacleGrid[0][j] == 0) dp[0][j] = dp[0][j - 1];
// 3. 循环填充
for (int i = 1; i < m; i++) {
for (int j = 1; j < n; j++) {
if (obstacleGrid[i][j] == 0) dp[i][j] = dp[i - 1][j] + dp[i][j - 1];
else dp[i][j] = 0;
}
}
// 4. 返回结果
return dp[m - 1][n - 1];
}
}