因为它,差点无缘大厂梦!!!

前言

今天,小莱在leetcode上闲逛,突然眼前一亮,咦!这不是去年来百度二面时的一道算法题吗?没想到在这遇到了。想当时险些栽到上边,不过最后千钧一发之际,还是想到了解决方法,顺利拿到offer 。

画外音:后来,在小米的面试环节中也遇到了此题。

那么,今天小莱就给大家分享下这道动态规划题。 

题目:

一个机器人位于一个 m × n 网格的左上角(起始点在下图中标记为“Start” )。

机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为“Finish”)。

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

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

例如,上图是一个7 × 3 的网格。有多少可能的路径?

画外音:Leetcode第62题,中等/难度。

不同路径

我们由终点位置倒推,从图中可以看出,想要到达终点,A、B两点是必经之路。那么,我们想要得到起点到终点的路径数,计算出到达A、B两点的路径总数不就能够得出来了吗?但是A、B两点的路径数如何得出呢。

我们不妨再往前推,到达A点需要经过C或者D这两点,到达A点的路径数可以通过到达C、D两点的路径总数得知。

 

 

同样地,到达B点需要经过D点或E点,到达B点的路径数可以通过到达D、E两点的路径总数得知。

 

 

到这,聪明的你有没有发现规律:

每一个点可到达路径数 = 其相邻左边点可到达路径数 + 其相邻上边点可到达路径数

现在,我们可以回到起点了。 

我们可以把m×n方格看作一个二维数组,数组中的每个元素表示:

起点到该方格的路径数

起点到该方格的路径数

起点到该方格的路径数

(默念三遍!!!)

如下图中,机器人到达第X行(仅第0行)或第Y列(仅第0列)中的任意方格都只有一条路径。因此,我们将第X行、第Y列的方格元素都置为1。 

接着,我们继续向其它点走。现在分别经过路径一、路径二走到了S点,因此到达S点的路径有2条。

 

最终,我们得到这样一张网格,每个格子里记录了起点到该格的路径数。 

 

但是如何用代码表示呢?上边提到,我们可以将其看作一个二维数组v[m][n]。初始时,将第0行、第0列赋值为1。通过双层循环,将目标点的上边元素与左边元素相加,即可得到当前路径数。

代码实现:

int uniquePaths(int m, int n){
    if (m == 1 || n == 1) {
        return 1;
    }

    int i, j;
    int v[m][n];

    for (i = 1; i < m; i++) {
        v[i][0] = 1;
        for (j = 1; j < n; j++) {
            v[0][j] = 1;
            v[i][j] = v[i][j-1] + v[i-1][j];
        }
    }

    return v[m-1][n-1];
}

 

画外音:本文使用C语言实现,但是不会涉及复杂的语言特性,所以无需担心看不懂。另外,代码实现小莱在leetcode亲测!!!

不同路径 II

进行到这里,我们就实现了机器人从起点到终点畅通无阻情况下所要走的路径。 

你可能注意到了,小莱重点标记了下『畅通无阻』这4个字,这说明还有存在障碍物的情况。那么现在我们就来看看,存在障碍物的情况下,机器人所走的路径数有多少。

画外音:此题为Leetcode第63题,中等/难度。

如图中,给定一个二维数组obstacleGrid[m][n],用1来表示障碍物,用0表示空位置。

同样地,我们还是用二维数组v[m][n]来表示机器人到达某个方格的路径数。

但是在处理时,与无障碍物不同的是,其不再是简单向右或向下移动。初始化和计算时要考虑障碍。

这里分为两种情况: 

1、当障碍物出现在第0行或第0列,此时一旦遇到障碍,后续方格无法到达,因此后续行列路径数只能为0;

画外音:这里只给出第0行、第0列路径数。

2、当障碍物出现在非第0行与第0列的任意位置时,如果当前方格为障碍物时,可以直接将该方格赋值为0;

 

 

现在我们可以通过代码来实现了,首先初始化二维数组v[m][n],值默认都为0。接着初始化第0行和第0列,当未遇到障碍物时路径数为1,否则为0,其后方格的路径也都为0。然后通过双层循环,将目标点的上边元素与左边元素相加,即可得到当前路径数(在这个过程中如果遇到障碍物的话其方格数为0)。

代码实现:

 

int uniquePathsWithObstacles(int** obstacleGrid, int obstacleGridSize, int* obstacleGridColSize){
    // m代表行 n代表列
    int m = obstacleGridSize, n = * obstacleGridColSize;
    if (obstacleGrid[0][0] == 1) {
        return 0;
    }

    int i, j;
    int v[m][n];
    memset(v, 0, m * n * sizeof(int));
    //初始化第一列
    for (i = 0; i < m; i++) {
        if (obstacleGrid[i][0] == 1) {
            break;
        }
        v[i][0] = 1;
    }
    //初始化第一行
    for (j = 0; j < n; j++) {
        if (obstacleGrid[0][j] == 1) {
            break;
        }
        v[0][j] = 1;
    }

    for (i = 1; i < m; i++) {
        for (j = 1; j < n; j++) {
            v[i][j] = obstacleGrid[i][j] == 1 ? 0 : (v[i][j-1] + v[i-1][j]);
        }
    }

    return v[m-1][n-1];
}

关于作者

作者:大家好,我是莱乌,BAT搬砖工一枚。从小公司进入大厂,一路走来收获良多,想将这些经验分享给有需要的人,因此创建了公众号「IT界农民工」。定时更新,希望能帮助到你。

 

 

posted @ 2020-10-24 19:02  *IT界农民工*  阅读(512)  评论(3编辑  收藏  举报