LeetCode 👉 HOT 100 👉 不同路径 - 中等题

462 阅读2分钟

「这是我参与2022首次更文挑战的第3天,活动详情查看:2022首次更文挑战」。

题目

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

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

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

示例1

Image

输入:m = 3, n = 7

输出:28

示例2

输入:m = 3, n = 2

输出:3

解释:

从左上角开始,总共有 3 条路径可以到达右下角。
1. 向右 -> 向下 -> 向下
2. 向下 -> 向下 -> 向右
3. 向下 -> 向右 -> 向下

思路

DFS暴力解法

  • 定义一个递归函数jump,接受当前机器人的位置坐标 [x, y]

  • 每次递归,做如下判断

    • 如果机器人到达终点 x == m && y == n,将结果 count++, 同时结束递归

    • 如果当前坐标 x < m,继续以参数 [x + 1, y] 执行递归函数

    • 如果当前坐标 y < n,继续以参数 [x, y + 1] 执行递归函数

  • 机器人初始坐标为 [1, 1],启动递归函数

  • 返回 count 即为所求

代码如下

    /**
     * @param {number} m
     * @param {number} n
     * @return {number}
     */
    var uniquePaths = function(m, n) {
        let count = 0;

        const jump = ([x, y]) => {
            if(x == m && y == n) {
                count++;
                return;
            }

            if(x < m) {
                jump([x + 1, y])
            }
            
            if(y < n) {
                jump([x, y + 1])
            }
        }

        jump([1, 1]);

        return count;
    };

上述解法的时间复杂度很高,在 LeetCode 提交的时候,不出意外的超时了

image.png 动态规划

如果想要用 动态规划 来解决这个问题,我们需要进行以下几个步骤的分析:

  • 定义 dp 数组元素的含义

  • 确定数组元素间的关系式

  • 确定边界、初始条件

对于本题,dp 数组显然是一个二位数组,可以用 dp[i][j] 表示从左上角走到 (i, j) 的路径数量,其中 0 <= i < m, 0 <= j < n;

那么对于数组间的关系式:对于 (i, j),由于题目要求机器人只能向下或者向右移动,那么走到 (i, j) 的上一步,只能为 (i - 1, j) 或者 (i, j - 1),所以显然有 dp[i][j] = dp[i - 1][j] + dp[i][j - 1];

边界就是刚刚指出的 0 <= i < m, 0 <= j < n,那么初始条件,是什么呢?思考一下就可得,dp[i][0] 都是等于 1 的,同时 dp[0][j] 都是等于 1 的

dp[m - 1][n - 1] 即为题目所求

代码如下

    /**
     * @param {number} m
     * @param {number} n
     * @return {number}
     */

    var uniquePaths = function(m, n) {
        var dp = new Array(m).fill(() => new Array(n).fill(0));

        for(let i = 0; i < m; i++) {
            dp[i][0] = 1;
        }

        for(let j = 0; j < n; j++) {
            dp[0][j] = 1
        }

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

        return dp[m - 1][n - 1]
    }

小结

暴力解法,可能是最直观的方法,但是当递归的次数增加时,如果不能很好剪枝,就会出现大量的重复计算问题。而对于效率要求较高的算法来说,在某些情况下可能会不太适用,这个时候就需要寻找另外的解法。

但是还是有一点是需要坚持的,暴力解会提供很多思考的方向,像如果存在重复的计算,可以尝试使用缓存已计算的结果,下次遇到时直接从缓存拿,也可能会提升很多效率。

# LeetCode 👉 HOT 100 👉 不同路径 - 中等题

合集:LeetCode 👉 HOT 100,有空就会更新,大家多多支持,点个赞👍

如果大家有好的解法,或者发现本文理解不对的地方,欢迎留言评论 😄