在问 · 算法题解

62. 不同路径

中等动态规划动态规划(一维滚动)力扣原题 ↗

题目描述

有一个 m 行 n 列的网格。机器人从左上角的格子出发,要走到右下角的格子。

每一步只能向右或向下移动一格。

返回从起点走到终点的不同路线总数。

示例 1
输入:m = 3, n = 7
输出:28
示例 2
输入:m = 3, n = 2
输出:3

解释:共 3 条路线:右下下、下下右、下右下。

数据范围

  • 1 <= m, n <= 100
  • 保证答案不超过 2 * 10^9。

解题思路:动态规划(一维滚动)

网格状态为上方和左方路径数之和,使用一维数组滚动每一行。

为什么正确

dp[j] 在更新前是上方格子的路径数,更新后是当前行该格的路径数。

复杂度分析

时间 O(mn),空间 O(n)。

易错点

一维压缩时必须从左到右更新,因为 dp[j-1] 需要是当前行的新值。

参考代码

Python、Java、C++、Go、JavaScript、TypeScript 六种语言,逻辑一致。

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        dp = [1] * n
        for _ in range(1, m):
            for j in range(1, n):
                dp[j] += dp[j - 1]
        return dp[-1]

载入编辑器,自己跑一遍 →

其他解法

动态规划通用、可扩展到带障碍物的情况;组合数学直接给出公式,O(min(m,n)) 时间、O(1) 空间,但只适用于无障碍的网格。

解法 2:组合数学 时间 O(min(m,n)),空间 O(1)

从左上角走到右下角,一共要走 m+n-2 步,其中恰好 m-1 步向下、n-1 步向右。不同路径数就是从 m+n-2 步里选出 m-1 步向下的方案数 C(m+n-2, m-1)。累乘时依次乘以 n, n+1, … 再除以 1, 2, …,每一步的中间结果都是组合数,一定能整除。

时间和空间都更优,但需要看出计数本质是组合数。累乘过程中要注意溢出,C++/Java 需要用 64 位整数。遇到障碍物(第 63 题)时这种方法就不适用了。

class Solution:
    def uniquePaths(self, m: int, n: int) -> int:
        # 从 m+n-2 步中选出 m-1 步向下
        ans = 1
        x = n
        for y in range(1, m):
            ans = ans * x // y
            x += 1
        return ans

动态规划 专题的其他题目

查看 动态规划 全部题目 →