漫画:BAT必考题目 (不同路径 - 障碍物版本)

今天是小浩算法“365刷题计划”第52天。昨天为大家分享了不同路径的DP解法之后,有很多小伙伴后台给我留言,说直接用公式法一步就可以得到答案。给你们点个赞!确实是这样,我没有用公式法的原因,是因为我的目的是想层层推进难度为大家分析不同路径这一类题型。后面我会单独拉出一系列,专门为大家讲解公式法一类的题目。

如果还没有学习上一篇内容,建议先进行学习:

漫画:BAT必考题目 (如何压缩状态完成不同路径题目)

01

PART

不同路径 - 障碍物

多了一点障碍物之后,题目会有何不同?(这可是困难题目哦~)

不同路径:一个机器人位于一个 m x n 网格的左上角,起始点在下图中标记为“Start”。机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角,在下图中标记为“Finish”。现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径? 

问总共有多少条不同的路径?

网格中的障碍物和空位置分别用 1 和 0 来表示。

说明:m 和 n 的值均不超过 100。

示例 1:

输入:

[

  [0,0,0],

  [0,1,0],

  [0,0,0]

]

输出: 2

解释:

3x3 网格的正中间有一个障碍物。

从左上角到右下角一共有 2 条不同的路径:

1. 向右 -> 向右 -> 向下 -> 向下

2. 向下 -> 向下 -> 向右 -> 向右

(瞪一瞪就全部掌握)

02

PART

题目分析

因为只是多了一点障碍物,题目的本质并没什么不同,所以直接进行分析即可。 

首先我们还是定义状态,DP[i][j]表示到达i行j列的最多路径。同时,因为第0行和第0列都只有一条路径,所以需要初始化为1。但有一点不一样的就是:如果在0行0列中遇到障碍物,后面的就都是0,意为此路不通

完成了初始化,下面就是状态转移方程。和没有障碍物的相比没什么特别的,仍然是dp[i][j] = dp[i-1][j] + dp[i][j-1]。唯一需要处理的是:如果恰好[i][j]位置上有障碍物,则dp[i][j]为0。比如下图,有dp[1][2]为0。

根据分析,得出代码:(今天翻java牌子)

 1//JAVA
 2class Solution {
 3    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
 4        int m = obstacleGrid.length;
 5        int n = obstacleGrid[0].length;
 6        int[][] dp = new int[m][n];
 7        if (obstacleGrid[0][0] != 1) {
 8            dp[0][0] = 1;
 9        }
10        for (int j = 1; j < n; j++) {
11            dp[0][j] = obstacleGrid[0][j] == 1 ? 0 : dp[0][j - 1];
12        }
13        for (int i = 1; i < m; i++) {
14            dp[i][0] = obstacleGrid[i][0] == 1 ? 0 : dp[i - 1][0];
15        }
16        for (int i = 1; i < m; i++) {
17            for (int j = 1; j < n; j++) {
18                dp[i][j] = obstacleGrid[i][j] == 1 ? 0 : dp[i - 1][j] + dp[i][j - 1];
19            }
20        }
21        return dp[m - 1][n - 1];
22    }
23}

郑重申明(读我的文章必看):

  • 本系列所有教程都不会用到复杂的语言特性,不需要担心没有学过相关语法,使用各语言纯属本人爱好。

  • 作为学术文章,虽然风格可以风趣,但严谨,我是认真的。本文所有代码均在leetcode上进行过测试运行。

  • 算法思想才是最重要的。

03

PART

代码优化

不啰嗦,我们当然要继续压缩内存

为了大家更好的理解代码,我们还是绘图说明。(我也太良心了,天天给你们画图!快帮我转发)假若我们的网格如下,其中黑色表示障碍物。

因为计算每一个格子能到达的最多路径,只需要左边和上边的元素,所以我们定义状态dp[j]表示到达当前行第j位置的最多路径。这里有一个需要额外说的,就是我们把dp[0]初始化为1,因为在到达第一行的第一个元素时,路径只有一个。下面的图,左边的表示当前网格,右边的是指网格中对应dp数组的值。

根据分析,得出代码:

 1//JAVA
 2class Solution {
 3    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
 4        int m = obstacleGrid.length;
 5        int n = obstacleGrid[0].length;
 6        int[] dp = new int[n];
 7        dp[0] = 1;
 8        for (int[] ints : obstacleGrid) {
 9            for (int j = 0; j < n; j++) {
10                if (ints[j] == 1) {
11                    dp[j] = 0;
12                } else if (j > 0) {
13                    dp[j] += dp[j - 1];
14                }
15            }
16        }
17        return dp[n - 1];
18    }
19}

(思考:上面的代码其实还可以优化内存,大家想想怎么做)

如果上面的题目感觉不太好理解,建议看一下我之前的几道动态规划讲解。基本都是先使用普通DP思路,然后再尝试压缩状态。可能会有一些帮助!

漫画:动态规划系列 第一讲

漫画:动态规划系列 第二讲

漫画:动态规划系列 第三讲

漫画:动态规划系列 第四讲
漫画:动态规划系列 第五讲

漫画:动态规划系列 第六讲

所以,今天的问题你学会了吗?评论区留下你的想法!

 小浩算法,每日

关注领取《图解算法》高清版

进群的小伙伴请加右侧私人微信(备注:进群)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值