返回
LeetCode:揭秘 HOT 100 经典题目“不同路径”的解题思路与优化策略
前端
2023-12-05 06:26:41
- 暴力递归
暴力递归是解决“不同路径”问题的最直观的方法,它的思路非常简单:从起点出发,你可以向右走或者向下走,每走一步,就递归地计算从该点到终点的不同路径数,最后将所有路径数相加即可。
function numDistinctPaths(grid) {
if (grid[0][0] === 1) {
return 0;
}
return numPathsFromCell(grid, 0, 0);
}
function numPathsFromCell(grid, row, col) {
if (row === grid.length - 1 && col === grid[0].length - 1) {
return 1;
}
let numPaths = 0;
if (row + 1 < grid.length && grid[row + 1][col] === 0) {
numPaths += numPathsFromCell(grid, row + 1, col);
}
if (col + 1 < grid[0].length && grid[row][col + 1] === 0) {
numPaths += numPathsFromCell(grid, row, col + 1);
}
return numPaths;
}
但是,暴力递归有一个致命的问题:当网格很大时,它会产生大量的重复计算,导致时间复杂度呈指数级增长。
2. 动态规划
为了解决暴力递归的效率问题,我们可以引入动态规划的思想。动态规划的本质是将大问题分解成若干个子问题,然后通过子问题的解来逐步解决大问题。对于“不同路径”问题,我们可以将网格划分为若干个小格子,然后计算每个小格子的不同路径数。当我们计算某个小格子的不同路径数时,我们可以直接使用已经计算过的子问题的解,从而避免重复计算。
function numDistinctPaths(grid) {
if (grid[0][0] === 1) {
return 0;
}
let dp = Array(grid.length).fill(0).map(() => Array(grid[0].length).fill(0));
dp[0][0] = 1;
for (let row = 0; row < grid.length; row++) {
for (let col = 0; col < grid[0].length; col++) {
if (grid[row][col] === 1) {
dp[row][col] = 0;
} else {
if (row - 1 >= 0) {
dp[row][col] += dp[row - 1][col];
}
if (col - 1 >= 0) {
dp[row][col] += dp[row][col - 1];
}
}
}
}
return dp[grid.length - 1][grid[0].length - 1];
}
动态规划法的时间复杂度为 O(mn),其中 m 和 n 分别是网格的行数和列数。空间复杂度也为 O(mn),因为我们需要存储每个小格子的不同路径数。
3. 记忆化搜索
记忆化搜索是一种优化动态规划的技巧。它通过将子问题的解存储起来,避免重复计算。对于“不同路径”问题,我们可以将计算过的子问题的解存储在哈希表中。当我们再次遇到同一个子问题时,我们就可以直接从哈希表中获取其解,从而节省大量的计算时间。
function numDistinctPaths(grid) {
if (grid[0][0] === 1) {
return 0;
}
let memo = {};
return numPathsFromCell(grid, 0, 0, memo);
}
function numPathsFromCell(grid, row, col, memo) {
if (row === grid.length - 1 && col === grid[0].length - 1) {
return 1;
}
let key = row + ',' + col;
if (memo[key] !== undefined) {
return memo[key];
}
let numPaths = 0;
if (row + 1 < grid.length && grid[row + 1][col] === 0) {
numPaths += numPathsFromCell(grid, row + 1, col, memo);
}
if (col + 1 < grid[0].length && grid[row][col + 1] === 0) {
numPaths += numPathsFromCell(grid, row, col + 1, memo);
}
memo[key] = numPaths;
return numPaths;
}
记忆化搜索法的