LeetCode Hot100(62/100)——62. 不同路径

文章目录

题目理解

我们可以把网格看成一个棋盘:

  • 起点:左上角
  • 终点:右下角
  • 允许动作:向右向下

m = 3, n = 7 为例,答案是 28

一个直观网格示意:

0 1 2 3 4 5 6
0 S
1
2 E

解法总览

不同路径
暴力递归
思路直观
指数级复杂度
记忆化搜索
递归 + 缓存
避免重复子问题
动态规划
二维DP
状态转移清晰
一维DP
空间优化
数学组合
本质是排列组合
复杂度最低


关键状态与转移

定义 f(i, j) 表示从起点走到格子 (i,j) 的路径数。

因为最后一步只能来自:

  • 上方 (i-1, j)(向下走一步到当前)
  • 左方 (i, j-1)(向右走一步到当前)

所以有经典转移方程:

f ( i , j ) = f ( i − 1 , j ) + f ( i , j − 1 ) f(i,j)=f(i-1,j)+f(i,j-1) f(i,j)=f(i−1,j)+f(i,j−1)

边界:

  • 第一行只能一直向右走,所以都是 1
  • 第一列只能一直向下走,所以都是 1

解法一:暴力递归

原理

从终点反推:

  • (i,j) 的路径数 = 到 (i-1,j) + 到 (i,j-1)
  • 递归到边界结束

问题

会重复计算大量子问题(例如 (m-2,n-2) 会被多次计算),时间复杂度指数级,LeetCode 会超时。

Java 代码

java 复制代码
class Solution {
    public int uniquePaths(int m, int n) {
        return dfs(m - 1, n - 1);
    }

    private int dfs(int i, int j) {
        if (i < 0 || j < 0) return 0;
        if (i == 0 || j == 0) return 1;
        return dfs(i - 1, j) + dfs(i, j - 1);
    }
}

复杂度

  • 时间复杂度:O(2^(m+n))(近似指数级)
  • 空间复杂度:O(m+n)(递归栈深度)

解法二:记忆化搜索(递归 + 缓存)

原理

在暴力递归基础上,增加一个 memo[i][j]

  • memo[i][j] 已算过,直接返回
  • 否则递归计算并存储

避免重复子问题后,复杂度降到多项式级别。

时序图

dfs(i,j) Solution 调用方 dfs(i,j) Solution 调用方 uniquePaths(m,n) dfs(m-1,n-1) dfs(i-1,j) dfs(i,j-1) 写入 memo[i][j] 返回 memo[i][j] 返回结果

Java 代码

java 复制代码
class Solution {
    private int[][] memo;

    public int uniquePaths(int m, int n) {
        memo = new int[m][n];
        return dfs(m - 1, n - 1);
    }

    private int dfs(int i, int j) {
        if (i < 0 || j < 0) return 0;
        if (i == 0 || j == 0) return 1;
        if (memo[i][j] != 0) return memo[i][j];

        memo[i][j] = dfs(i - 1, j) + dfs(i, j - 1);
        return memo[i][j];
    }
}

复杂度

  • 时间复杂度:O(m*n)
  • 空间复杂度:O(m*n)(memo)+ O(m+n)(递归栈)

解法三:二维动态规划

原理

递归改迭代,按行或按列填表。

  1. 创建 dp[m][n]
  2. 初始化第一行、第一列为 1
  3. (1,1) 开始:
    dp[i][j] = dp[i-1][j] + dp[i][j-1]
  4. 返回 dp[m-1][n-1]

流程图



开始
创建 dp[m][n]
第一行全部置 1
第一列全部置 1
双重循环 i=1..m-1, j=1..n-1
dp[i][j]=dp[i-1][j]+dp[i][j-1]
遍历结束?
返回 dp[m-1][n-1]
结束

Java 代码

java 复制代码
class Solution {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];

        for (int i = 0; i < m; i++) dp[i][0] = 1;
        for (int j = 0; j < n; j++) dp[0][j] = 1;

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

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

复杂度

  • 时间复杂度:O(m*n)
  • 空间复杂度:O(m*n)

解法四:一维动态规划(空间优化)

原理

观察二维 DP 转移式:

  • dp[i][j] 只依赖当前行左边值 dp[i][j-1]
  • 和上一行同列值 dp[i-1][j]

可以把二维压缩成一维数组 dp[j]

  • dp[j] 在更新前代表"上一行同列"
  • dp[j-1] 在更新后代表"当前行左侧"

转移:
d p [ j ] = d p [ j ] + d p [ j − 1 ] dp[j] = dp[j] + dp[j-1] dp[j]=dp[j]+dp[j−1]

Java 代码

java 复制代码
class Solution {
    public int uniquePaths(int m, int n) {
        int[] dp = new int[n];

        // 第一行全是1
        for (int j = 0; j < n; j++) dp[j] = 1;

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

        return dp[n - 1];
    }
}

复杂度

  • 时间复杂度:O(m*n)
  • 空间复杂度:O(n)

解法五:数学组合

原理

从起点到终点总共要走:

  • 向下 m-1
  • 向右 n-1

总步数 m+n-2,本质是从这些步中选哪几步向下(或向右):

ans = C ( m + n − 2 , m − 1 ) = C ( m + n − 2 , n − 1 ) \text{ans} = C(m+n-2, m-1) = C(m+n-2, n-1) ans=C(m+n−2,m−1)=C(m+n−2,n−1)

为什么好

  • 不需要 DP 表
  • 复杂度最低(线性于较小维度)

Java 代码(避免中间溢出)

java 复制代码
class Solution {
    public int uniquePaths(int m, int n) {
        int total = m + n - 2;
        int k = Math.min(m - 1, n - 1);

        long ans = 1;
        for (int i = 1; i <= k; i++) {
            ans = ans * (total - k + i) / i;
        }
        return (int) ans;
    }
}

复杂度

  • 时间复杂度:O(min(m,n))
  • 空间复杂度:O(1)

各解法对比

解法 时间复杂度 空间复杂度 说明
暴力递归 指数级 O(m+n) 思路简单,但会超时
记忆化搜索 O(m*n) O(m*n) 递归写法友好
二维 DP O(m*n) O(m*n) 最经典,容易理解
一维 DP O(m*n) O(n) 工程上常用优化
数学组合 O(min(m,n)) O(1) 最简洁高效

推荐写法

面试/笔试建议优先:

  1. 二维 DP(解释最直观)
  2. 一维 DP(展示优化能力)
  3. 数学组合(展示抽象能力)
相关推荐
jing-ya1 小时前
day 50 图论part2
java·算法·深度优先·图论
仰泳的熊猫1 小时前
题目2268:蓝桥杯2016年第七届真题-密码脱落
数据结构·c++·算法·蓝桥杯
我能坚持多久2 小时前
【初阶数据结构09】——对堆用法的深入刨析
数据结构·算法
kaikaile19952 小时前
基于PCNN和NSCT的图像融合MATLAB实现
开发语言·图像处理·算法·matlab
Zik----2 小时前
cs研究生面试机试题(持续更新)
算法
1231566802 小时前
PAT 1017 A除以B
c语言·数据结构·算法·pat考试
努力学算法的蒟蒻2 小时前
day112(3.14)——leetcode面试经典150
面试·职场和发展
芯片-嵌入式2 小时前
具身智能(2):OpenExplorer下的模型量化
人工智能·深度学习·算法
Yusei_05232 小时前
C++14入门
c++·算法