看我如何破解机器人找路难题(LeetCode 63)
今天来挑战 LeetCode 63 题,这题如同给机器人安排了一场 “迷宫冒险”🤖。给定一个m x n的网格,机器人从左上角grid[0][0]出发,前往右下角grid[m - 1][n - 1],每次仅能向下或向右移动一步。关键是网格中存在 “陷阱”(障碍物用 1 表示,空地用 0 表示) ,需要找出有多少条不同的安全路径能抵达终点,这可够机器人 “头疼” 的。别着急,接下来就用代码 “拯救” 它,带你一起攻克这道题!
题目描述
给定一个m x n的整数数组grid,机器人初始位于左上角,每次只能向下或向右移动一步,网格中的障碍物和空位置分别用1和0表示,求机器人到达右下角的不同路径数量。
想象一下,机器人就像方格世界里的小探险家,有些方格被 “施了魔法” 变成障碍物,它必须小心翼翼地避开,寻找通往终点的道路,是不是很有意思?
代码实现
class Solution {
public int uniquePathsWithObstacles(int[][] obstacleGrid) {
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
int[] dp = new int[n];
dp[n - 1] = obstacleGrid[m - 1][n - 1] == 1? 0 : 1;
for (int i = m - 1; i >= 0; i--) {
int tmp = dp[n - 1];
dp[n - 1] = obstacleGrid[i][n - 1] == 1 || tmp == 0? 0 : 1;
for (int j = n - 2; j >= 0; j--) {
int tmp2 = dp[j];
if (obstacleGrid[i][j] == 1) {
dp[j] = 0;
} else {
if (i < m - 1) {
dp[j] += dp[j + 1];
} else {
dp[j] = dp[j + 1];
}
}
tmp = tmp2;
}
}
return dp[0];
}
}
接下来,让我们像 “剥洋葱” 一样,逐步剖析这段代码的运作逻辑。
代码思路分析
1. 获取网格大小
int m = obstacleGrid.length;
int n = obstacleGrid[0].length;
这一步就好比为机器人测量 “地图” 的尺寸,m是网格的行数,n是网格的列数。只有了解这些信息,机器人才能心中有数,规划自己的 “路线图”。
2. 初始化动态规划数组
int[] dp = new int[n];
dp[n - 1] = obstacleGrid[m - 1][n - 1] == 1? 0 : 1;
此处创建了一个一维数组dp,其长度为列数n。为何使用一维数组呢?这就像是为机器人准备了一个 “小账本” ,用于记录从当前位置到终点的不同路径数量。首先查看右下角的位置,如果右下角是障碍物(obstacleGrid[m - 1][n - 1] == 1),那么机器人肯定无法到达,路径数为 0;否则,路径数为 1,毕竟已经到达终点。
3. 动态规划递推
for (int i = m - 1; i >= 0; i--) {
这个外层循环从最后一行开始,向上遍历每一行。就好像机器人从下往上 “复盘” 自己的路线,思考如何从上面的位置移动到下面的位置。
处理最右边的列
int tmp = dp[n - 1];
dp[n - 1] = obstacleGrid[i][n - 1] == 1 || tmp == 0? 0 : 1;
先将原来右下角位置的路径数存储到tmp中。然后查看当前行最右边的位置,如果该位置是障碍物,或者从下面来的路径数为 0(表明下面也无法到达),那么这个位置的路径数就是 0;否则为 1,因为只能从下面过来。
处理其他位置
for (int j = n - 2; j >= 0; j--) {
int tmp2 = dp[j];
if (obstacleGrid[i][j] == 1) {
dp[j] = 0;
} else {
if (i < m - 1) {
dp[j] += dp[j + 1];
} else {
dp[j] = dp[j + 1];
}
}
tmp = tmp2;
}
这个内层循环从倒数第二列开始,向左遍历每一列。对于每个位置,如果是障碍物,路径数必然为 0,就如同前面有一堵墙,机器人无法通过。如果不是障碍物,并且不是最后一行(i < m - 1),那么这个位置的路径数就是从右边来的路径数加上从下面来的路径数,毕竟机器人可以从右边或者下面到达这个位置;如果是最后一行,那就只能从右边来,路径数就等于从右边来的路径数。最后,将原来dp[j]的值存储到tmp中,方便下一次循环使用。
4. 返回结果
return dp[0];
最后,dp[0]中存储的就是从左上角到右下角的不同路径数量,直接返回即可大功告成!机器人 “冒险之旅” 的路线数量就这样被成功计算出来啦!
掌握了方法,这道题其实并不难。以后遇到类似的题目,相信大家都能轻松应对!一起加油,向着更多的算法难题迈进,加油💪!