【记忆化搜索】不同路径

文章目录

题目链接:62. 不同路径


一、题目解析

记忆化搜索 是一种通过记录已经遍历过的状态的信息,从而避免对同一状态重复遍历的搜索实现方式(是一种常见的动态规划实现方式)。

可以通过记忆化搜索来优化 DFS(剪枝)以提高算法效率。

回到题目,本题给出一个 m x n 网格。机器人的起始位置在网格的左上角(坐标 1, 1),并且每次只能向下或者向右移动一步,如果机器人要到达网格的右下角,总共有多少条不同的路径?我们需要返回路径条数。

例1:m = 3, n = 7

返回的路径条数是 28。


DFS:深度优先搜索

算法原理

我们的目标是 找到机器人从起始位置【1, 1】到达终点【m, n】的路径数 ,并且根据题目的规则(机器人每次只能向下或者向右移动一步)可以知道:到达【m, n】这个位置的方式只有两个,一个是从该位置的上方(【m-1, n】)往下走一步,另一个则是从该位置的左方(【m, n-1】)往右走一步:

要想知道到达【m-1, n】和【m, n-1】的路径数,也是一样:找出到达该位置的上方和左方的位置的路径数。这就是相同的问题,我们可以使用递归来解决。

dfs 函数

函数头

我们给 dfs 函数设置的任务是:找出到达【row, col】位置的路径数 ,其中 row 和 col 是位置的坐标,作为参数,返回值为 int。

java 复制代码
int dfs(int row, int col);

函数体

由于本题起始位置的坐标是【1, 1】,因此递归出口需要判断 row 和 col 为 0 的情况、为 1 的情况:

  1. row 和 col 为 0:【0, 0】是非法的坐标,无法到达这个位置,即 0 条路径
  2. row 和 col 为 1:【1, 1】是起始位置,到达这个位置的路径数只有 1 条

然后便是递归展开。

代码实现

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

    // dfs任务:返回到达[row,col]位置的路径数
    public int dfs (int row, int col) {
        // 非法情况(下标从1开始)
        if (row == 0 || col == 0) {
            return 0;
        }
        // 位于起始位置
        if (row == 1 && col == 1) {
            return 1;
        }
				
        // 递归展开
        return dfs(row-1, col) + dfs(row, col-1);
    }
}

记忆化搜索

使用递归的方法由于时间复杂度达到指数级别,超时无法通过。

当我们求 dfs(4, 4) 时,递归的部分展开图如下:

可以发现有很多的展开都是重复的,正是大量重复的递归展开导致超时,我们可以想办法通过剪枝来减少重复的递归展开操作,从而提高算法的效率。

算法原理

记忆化搜索的本质就是 "带着记忆递归搜索" ,而 记忆数组/备忘录 正是这类问题的关键。

本题有两个变量------ dfs 函数的两个参数,我们将这两个参数坐标所对应的位置的路径数记录在记忆数组/备忘录中,等到需要这个位置的路径数时,直接从记忆数组/备忘录中取即可,无需再次递归展开了。

记忆数组

本题的记忆数组是一个二维数组,值是到达位置【row, col】的路径数。本题无需对其做初始化操作,默认值为0。

  1. 在递归展开之前,先查看记忆数组/备忘录
  2. 在递归展开之后,先将得到的结果存入记忆数组/备忘录,再返回

代码实现

java 复制代码
class Solution {
    int[][] memo; // 记忆数组

    public int uniquePaths(int m, int n) {
        // 初始化
        memo = new int[m+1][n+1];

        return dfs(m, n);
    }

    // dfs任务:返回到达[row,col]位置的路径数
    public int dfs (int row, int col) {
        // 递归展开之前,先查看记忆数组
        if (memo[row][col] != 0) {
            return memo[row][col];
        }

        // 非法情况(下标从1开始)
        if (row == 0 || col == 0) {
            return 0;
        }
        // 位于起始位置
        if (row == 1 && col == 1) {
            memo[row][col] = 1;
            return 1;
        }

        // 递归展开之后先将结果存入记忆数组
        memo[row][col] = dfs(row-1, col) + dfs(row, col-1);

        return memo[row][col];
    }
}

文章到这里就告一段落啦,若有错误请尽管指出~

完

相关推荐
微尘hjx8 小时前
【ByteTrack 04】多轨迹算法ByteTrack改进点
算法·yolo·目标检测·目标跟踪·bytetrack·ultralytics·车跟踪
云和数据.ChenGuang8 小时前
Python 重写(Override)深度解析:从 MRO 到 super() 的完整机制
java·开发语言·人工智能·python·langchain·1024程序员节
摇滚侠8 小时前
《On Java 中文版 基础卷》阅读笔记 实现隐藏 12
java·数据库·笔记
silvamux_10 小时前
10款模型写种草笔记:可发布性、返工来源与成本数据缺口复盘
java·数据库·笔记
步行cgn11 小时前
StringHttpMessageConverter 详解:Spring MVC 中字符串读写的默认转换器
java·spring·mvc
摇滚侠11 小时前
《On Java 中文版 基础卷》阅读笔记 实现隐藏 11
java·笔记·python
小蒜学长11 小时前
基于Spring Boot+Vue3的在线医疗咨询系统的设计与实现(代码+数据库+LW)
java·spring boot·后端·在线问诊·在线医疗咨询系统
Deng桑11 小时前
SpringAI写第一个Agent-把工单循环跑起来
java·agent·工具调用·spring ai
小蒋观天下12 小时前
雷击与浪涌防护:前端SPD选型、接地网误区,接地不当反而引入干扰
深度学习·算法·机器学习