【记忆化搜索】不同路径

文章目录

题目链接: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];
    }
}

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

完

相关推荐
Sarvartha3 小时前
final 关键字
java·开发语言
2601_952047793 小时前
单一策略深度教程:用轻易云把集成任务的报错实时推送到钉钉机器人
java·机器人·钉钉
yi0113 小时前
LeetCode 219:存在重复元素 II——哈希表记录“最近一次出现的位置”
数据结构·人工智能·笔记·python·算法·leetcode·哈希表
数据狐(Datafox)4 小时前
淘宝图片搜索 API 落地实战:基于以图搜货搭建跨境电商选品系统
java·大数据·微服务
Escalating_xu6 小时前
【C 语言】数据在内存中的存储:补码、大小端、整型陷阱与 IEEE 754 全解析
java·c语言·网络
灯澜忆梦6 小时前
【面向对象编程C++】| 基础语法
java·c++·算法
小蒋观天下6 小时前
专项方案:大场景港口AI安防、多干扰环境下的算法调优与落地实操
人工智能·深度学习·算法·安全·机器学习·计算机视觉·ai大模型
一个风轻云淡6 小时前
GCC 和 GDB命令简单解读
java·linux·前端