【每日天学习一点算法 2026/03/31】不同路径

每日天学习一点算法 2026/03/31

题目:不同路径

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

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

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

动态规划

这个题有点像爬楼梯

我们假设 dp[i][j] 是到达位置 (i, j) 的方法总数,那么在未触及边界的情况下 dp[i][j] = dp[i - 1][j] + dp[i][j - 1]

typescript 复制代码
function uniquePaths(m: number, n: number): number {
  const dp = new Array(m).fill(new Array(n).fill(1)) // 准备 dp 数组
  for (let i = 0; i < m; i++) {
    for (let j = 0; j < n; j++) {
      if (i === 0 && j === 0) continue // 第一个格子直接跳过
      if (i === 0) {
        // 没有上一行 
        dp[i][j] = dp[i][j - 1]
        continue
      }
      if (j === 0) {
        // 没有上一列
        dp[i][j] = dp[i - 1][j]
        continue
      }
      dp[i][j] = dp[i - 1][j] + dp[i][j - 1]
    }
  }
  return dp[m - 1][n - 1]
};

我们可以注意到,每次只会用到 dp[i][j - 1] 和 dp[i - 1][j]

dp[i][j - 1]好办,因为我们是一行一行的遍历的,所以我们只用记录上一次遍历的dp 值就行了

dp[i - 1][j]就比较麻烦了,我们需要一个数组来记录上一行的 dp 值

typescript 复制代码
function uniquePaths(m: number, n: number): number {
  let topDps = []
  let leftDp = 1
  for (let i = 0; i < m; i++) {
    const arr = []
    for (let j = 0; j < n; j++) {
      if (i === 0 && j === 0) {
        // 第一行的第一个元素直接填入 1 
        arr.push(1)
        continue
      }
      if (i === 0) {
        // 第一行全都只有一种走法
        arr.push(leftDp)
        continue
      }
      if (j === 0) {
        // 第一列走法都一样
        leftDp = topDps[j]
        arr.push(leftDp)
        continue
      }
      // 记录其他位置走法
      leftDp = leftDp + topDps[j]
      arr.push(leftDp)
    }
    // 每行遍历完,重新赋值 leftDp 和 topDps
    leftDp = topDps[0]
    topDps = arr
  }
  return topDps[n - 1]
};
组合数学

我们可以知道,走到左下角一共要往下走 m - 1 ,往右走 n - 1 步,这个问题就可以转换成总共要走 m + n - 2 步,其中 m - 1 步的走法不一样,一共有多少种走法也就是:

由于没有 JS 没有阶乘函数,我们可以写一个阶乘方法,也可以写一个计算组合数的方法,我们这里直接写计算组合数方法,我们直接看C(m, n)更好理解一点:

我们把分子的乘法修改一些就可以变成 (m - n + 1)(m - n + 2)...(m - n + (n - 1))(m - n + n)

刚好对应分子的阶乘 1 * 2 * ... * (n - 1) * n

这样直接循环就可以得出组合数结果

typescript 复制代码
function uniquePaths(m: number, n: number): number {
  // 组合数计算方法
  function compose (m: number, n: number) {
    n = Math.min(n, m - n) // 取较小的一边减少循环
    let res = 1
    // 循环计算结果
    for (let i = 1; i <= n; i++) {
      res = res * (m - n + i) / i
    }
    return res
  }
    
  // 返回 C(m + n - 2, m - 1) 的组合数
  return compose(m + n - 2, m - 1)
};

题目来源:力扣(LeetCode)

相关推荐
海绵宝宝转agent3 小时前
learn-claude-code第1-5章开源学习笔记分享
人工智能·笔记·python·学习
每天都要写算法(努力版)3 小时前
【行业前沿报告】DAgger:让智能体在自己走到的状态上学习
人工智能·学习·机器学习
hetao17338374 小时前
2026-10-03~04 hetao1733837 的刷题记录
c++·算法
Zootopia6265 小时前
飞行力学知识梳理1|飞行性能与稳定性
人工智能·python·算法·机器学习·无人机·学习方法·信息与通信
longlongzihan5 小时前
从LeetCode 70. 爬楼梯看动态规划:如何精准推导状态转移方程?
c++·算法·leetcode·动态规划
2601_960356386 小时前
2027校招采购岗解析:数学基础如何迁移到需求预测、成本与供应商分析
人工智能·算法
h_a_o777oah7 小时前
【树论】树链剖分:将树形结构转化为线性结构以处理树上路径问题(洛谷 P3384 附C++代码模板)
数据结构·算法·线段树·acm·树链剖分·树论·重链剖分
HEJOO97 小时前
指针的算术运算详解
java·数据结构·算法
sunshine22 girl7 小时前
Java学习六 Java常见API-2--String-3-字符串的截取替换和其他方法
java·开发语言·学习
Coder-magician7 小时前
《代码随想录》刷题打卡day47:并查集-part01
数据结构·算法·图论