当前位置: 首页 > article >正文

力扣第 62 题(Unique Paths)两种递归实现

直接递归的效率会非常低,因为会重复计算许多子问题。这种方法可以结合记忆化搜索(递归 + 缓存)优化效率,使其在合理的时间内求解问题。


递归解法

1. 基本递归(不推荐)

直接递归的思路是,从起点到终点有两种选择:向下或向右。总路径数等于向下和向右的路径数之和:

  • 如果从位置 ( i , j ) (i, j) (i,j) 出发:

    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)

递归终止条件:

  • 如果机器人超出边界,返回 0。
  • 如果到达右下角,返回 1。
int uniquePathsRecursive(int m, int n) {
    if (m == 1 || n == 1) {
        return 1; // 到达边界,只有一条路径
    }
    return uniquePathsRecursive(m - 1, n) + uniquePathsRecursive(m, n - 1);
}

问题

  • 时间复杂度: O ( 2 m + n ) O(2^{m+n}) O(2m+n),因为递归会重复计算大量相同的子问题,效率非常低。

2. 记忆化搜索(递归 + 缓存)

为了解决重复计算的问题,可以使用一个二维数组缓存已经计算过的结果。

思路:
  • 创建一个二维数组 memo[m][n],用来存储从 ( i , j ) (i, j) (i,j) 出发到右下角的路径数。
  • 如果 memo[i][j] 已经计算过,直接返回。
  • 否则按照递归公式计算,并将结果存储到 memo[i][j] 中。
实现代码:
#include <stdio.h>
#include <stdlib.h>

// 递归辅助函数
int dfs(int m, int n, int i, int j, int** memo) {
    // 如果超出边界,返回 0
    if (i >= m || j >= n) {
        return 0;
    }
    // 如果到达终点,返回 1
    if (i == m - 1 && j == n - 1) {
        return 1;
    }
    // 如果已经计算过,直接返回缓存的结果
    if (memo[i][j] != -1) {
        return memo[i][j];
    }
    // 递归计算路径数,并存入缓存
    memo[i][j] = dfs(m, n, i + 1, j, memo) + dfs(m, n, i, j + 1, memo);
    return memo[i][j];
}

// 主函数
int uniquePaths(int m, int n) {
    // 创建缓存数组并初始化为 -1
    int** memo = (int**)malloc(m * sizeof(int*));
    for (int i = 0; i < m; i++) {
        memo[i] = (int*)malloc(n * sizeof(int));
        for (int j = 0; j < n; j++) {
            memo[i][j] = -1;
        }
    }

    // 调用递归函数
    int result = dfs(m, n, 0, 0, memo);

    // 释放内存
    for (int i = 0; i < m; i++) {
        free(memo[i]);
    }
    free(memo);

    return result;
}

int main() {
    int m = 3, n = 7;
    printf("不同路径的数量: %d\n", uniquePaths(m, n));
    return 0;
}

复杂度分析

时间复杂度
  • 在记忆化搜索中,每个状态 ( i , j ) (i, j) (i,j) 最多计算一次,因此总的时间复杂度为 O ( m × n ) O(m \times n) O(m×n)
空间复杂度
  • 递归栈空间复杂度为 O ( m + n ) O(m + n) O(m+n)(递归深度)。
  • 记忆化数组的空间复杂度为 O ( m × n ) O(m \times n) O(m×n)

总结

  • 小规模问题:可以使用递归解法,简单直观。
  • 中等规模问题:使用记忆化搜索或动态规划,效率高且容易实现。
  • 大规模问题:推荐组合数学解法,效率最高,但适用范围有限。

http://www.kler.cn/a/409320.html

相关文章:

  • 安宝特方案 | AR助力紧急救援,科技守卫生命每一刻!
  • SATA接口不通分析案例分享
  • 无线图传下的低延迟视频传输播放技术探讨
  • Vue 动态给 data 添加新属性深度解析:问题、原理与解决方案
  • android bindService打开失败
  • Android 常用命令和工具解析之内存相关
  • 40分钟学 Go 语言高并发:原子操作与CAS
  • nature communications论文 解读
  • 泷羽sec-----shell编程(完结)
  • 修复HIve表乱码问题
  • C++学习笔记4——名称空间
  • 部署一套开源客服系统,用户需要准备什么设备?
  • QT与嵌入式——搭建串口
  • cocoscreater3.8.4生成图集并使用
  • 青训10_1121_01_游戏排名第三大的分数
  • C 标准库 - <signal.h>
  • Roslyn和csc的关系?C#编程语言的命令行用法?C#编译器支持的版本?
  • HarmonyOS Next 简单上手元服务开发
  • 无插件直播流媒体音视频播放器EasyPlayer.js播放器的g711系列的音频,听起来为什么都是杂音
  • 国内外优秀的视频提取音频在线工具分享
  • Vue 动态给 data 添加新属性深度解析:问题、原理与解决方案
  • 应急响应靶机——linux1
  • 5、AI测试辅助-生成测试用例思维导图
  • C语言练习.if.else语句.strstr
  • 存储过程 与 表值函数
  • 【jvm】解释器