【JS每日一算法】57.不同路径II(深度优先、动态规划)

285 阅读2分钟

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

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

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

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

提示:

  • m == obstacleGrid.length
  • n == obstacleGrid[i].length
  • 1 <= m, n <= 100
  • obstacleGrid[i][j]01

示例:

robot1.jpg

输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3 网格的正中间有一个障碍物。
从左上角到右下角一共有 2 条不同的路径:
1. 向右 -> 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右 -> 向右

题解:

更多JS版本题解点击链接关注该仓库👀

/**
 * @description: dfs  TC:O(2^n)  SC:O(1)
 * @author: JunLiangWang
 * @param {*} obstacleGrid  给定m x n网格
 * @return {*}
 */
function dfs(obstacleGrid) {
    /**
     * 该方案使用深度优先遍历的方式,使用递归模拟机器人行进过程
     */

    // 记录路径数量
    let pathCount = 0,
        // x最大值
        maxX = obstacleGrid[0].length - 1,
        // y最大值
        maxY = obstacleGrid.length = 1;
    /**
     * @description: 递归回溯算法
     * @author: JunLiangWang
     * @param {*} x   当前机器人X坐标
     * @param {*} y   当前机器人Y坐标
     * @return {*}
     */
    function recursionBacktracking(x, y) {
        // 如果当前路径为石头,直接返回
        if (obstacleGrid[y][x] === 1) return;
        // 当机器人到达终点
        if (y === maxY && x === maxX) {
            // 路径数量加1
            pathCount++;
            return;
        }
        // 如果未达到终点

        // 如果并未达到横坐标边界,则x+1继续递归
        if (y < maxY) recursionBacktracking(x, y + 1);
        // 如果并未达到纵坐标边界,则y+1继续递归
        if (x < maxX) recursionBacktracking(x + 1, y);
    }
    // 执行递归
    recursionBacktracking(0, 0);
    // 返回结果
    return pathCount;
}


/**
 * @description:  动态规划   TC:O(n^2)  SC:O(n^2)
 * @author: JunLiangWang
 * @param {*} obstacleGrid 给定m x n网格
 * @return {*}
 */
function dp(obstacleGrid) {
    /**
     * 该方案使用动态规划的方式,定义一个(m+1)*(n+1)的矩阵(DPArray),其中矩阵的
     * 某一个元素,例如DPArray[i][j]表示到达(j,i)总共有多少条路径,已知
     * 机器人只能向下/向右移动,因此到达(j,i)有多少条路径就等于到达上一格
     * 即(j-1,i)与到达左一格即(j,i-1)的路径数量之和,公式则为:
     * DPArray[i][j]=DPArray[i-1][j]+DPArray[i][j-1],之所以是定义(m+1)*(n+1)的
     * 矩阵就是方便该处获取到DPArray[i-1][j]与DPArray[i][j-1]的值,如果
     * obstacleGrid[i-1][j-1]等于1,证明当前坐标有障碍物,此时DPArray[i][j]应等于0。
     * 最终DPArray最后一个元素则为达到终点的总数量
     * 
     */

    let m = obstacleGrid.length, n = obstacleGrid[0].length,
        // 定义一个(m+1)*(n+1)的矩阵
        DPArray = new Array(m + 1).fill(0).map(() => new Array(n + 1).fill(0));
    // 初始化(0,1)处路径数量为1,由于(1,1)处的路径数量肯定是为1的,而(1,1)处路径数量
    // 等于(1,0)的路径数量加上(0,1)的路径数量,因此需要先将两者其一初始化为1
    DPArray[0][1] = 1;
    // 从(1至m,1至n)遍历数组
    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; j++) {
            if (obstacleGrid[i - 1][j - 1] === 1)
                DPArray[i][j] = 0;
            else
                // 到达(j,i)的路径数量就等于到达上一格即(j-1,i)与到达左一格即(j,i-1)的路
                // 径数量之和,即:DPArray[i][j]=DPArray[i-1][j]+DPArray[i][j-1]
                DPArray[i][j] = DPArray[i - 1][j] + DPArray[i][j - 1];
        }
    }
    // 返回结果
    return DPArray[m][n];
}

来源:力扣(LeetCode)