[算法]力扣刷题-动态规划 - 不同路径

2023-11-05

题目:

一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为 “Start” )。
机器人每次只能向下或者向右移动一步。机器人试图达到网格的右下角(在下图中标记为 “Finish” )。 问总共有多少条不同的路径?

示例 1:
在这里插入图片描述
输入:m = 3, n = 7 输出:28


示例 2:
输入:m = 3, n = 2
输出:3
解释: 从左上角开始,总共有 3 条路径可以到达右下角。

  1. 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右
  3. 向下 -> 向右 -> 向下


提示:

1 <= m, n <= 100
题目数据保证答案小于等于 2 * 109

链接:https://leetcode-cn.com/leetbook/read/path-problems-in-dynamic-programming/rtwu06/


思路:

看到题目,基本确认是动态规划类问题。

我的思路是从终点向起点递归反推。首先确认状态转移方程:

因为每一步只能向下或向右移动,所以对于每一步的终点来说,只能是从上或从左移动而来。

因此起点走到点(x,y)的所有路径就是起点走到(x,y)上方点的所有路径加上起点走到(x,y)左方点的所有路径数量和。

即f(x,y) = f(x-1,y)+f(x,y-1)

当然有两种特殊情况:x为0或y为0,也即点在上边界一排或左边界一排时。
以上边界为例,上边界的点没有上方而来的路径,只有左方而来的路径。
因此y为0时公式为f(x,y) = f(x,y-1),但继续推,(x,y-1)这个点同样只有左方而来的点,只有一条路径最终指向了起点。因此上边界的所有点可以直接认定为路径数为1。

左边界同理。

因此状态转移方程为:

f(x,y) = 
{
    f(x-1,y)+f(x,y-1), (x>0 && y>0)
    1,                 (x==0 || y==0)
}

以题目中给出的3*7大小的方格为例,使用图形表示解法步骤如下:
在这里插入图片描述在这里插入图片描述


编码:

将状态转移方程转换为递归代码:

int uniquePaths_recursion(int m, int n)
{
    if(m==0 || n==0)
    {
        return 1;
    }

    return uniquePaths_recursion(m-1, n) + uniquePaths_recursion(m, n-1);
}

int uniquePaths(int m, int n)
{
    return uniquePaths_recursion(m-1, n-1);
}

不出所料 超时了。。。
在这里插入图片描述


分析:

超时的原因很明显,因为部分方格在递归算法中被重复计算了。

以3*3的矩阵为例,中间一格(1,1),会在(1,2)点作为左方时执行一遍递归,又会被(2,1)点作为上方时执行一遍递归。

在更大尺寸的矩阵中重复执行计算的格子就更多了,也就导致了算法执行超时。


修改:

老办法,空间换时间。
题目中有说明m,n<=100,直接创建一个100*100的二维数组,用于存储每个方格计算出的路径数。
如果该坐标在数组中的值非0,说明之前计算过路径数,直接使用即可,反之,进行递归计算。

int uniquePaths_recursion(int m, int n, int buf[100][100])
{
    if(m==0 || n==0)
    {
        buf[m][n] = 1;
        return 1;
    }

    int up = 0, left = 0;
    if(!buf[m-1][n])
    {
        up = uniquePaths_recursion(m-1, n, buf);
    }
    else
    {
        up = buf[m-1][n];
    }

    if(!buf[m][n-1])
    {
        left = uniquePaths_recursion(m, n-1, buf);
    }
    else
    {
        left = buf[m][n-1];
    }
    buf[m][n] = up+left;
    return buf[m][n];
}

int uniquePaths(int m, int n)
{
    int buf[100][100] = {0};
    int ret = uniquePaths_recursion(m-1, n-1, buf);
    return ret;
}

在这里插入图片描述


优化

m,n在不是100时使用二维数组有点浪费,想要进一步优化内存。

由于C语言的特性问题,如果还是想以二维的形式组织缓存表,列数是需要固定的,
也就是只能优化到m*100,因此直接将二维的表格使用一维形式存储数据(反正二维数组在内存中也是一样的连续内存),根据传入的m,n计算大小malloc内存。

int uniquePaths_recursion(int n, int m_curr, int n_curr, int *buffer)
{
    if(m_curr==0 || n_curr==0)
    {
        return 1;
    }

    int up = 0, left = 0;
    if(!(*(buffer+((m_curr-1)*n+n_curr))))
    {
        up = uniquePaths_recursion(n, m_curr-1, n_curr, buffer);
    }
    else
    {
        up = *(buffer+((m_curr-1)*n+n_curr));
    }

    if(!(*(buffer+(m_curr*n+n_curr-1))))
    {
        left = uniquePaths_recursion(n, m_curr, n_curr-1, buffer);
    }
    else
    {
        left = *(buffer+(m_curr*n+n_curr-1));
    }
    *(buffer+(m_curr*n+n_curr)) = up+left;
    return up+left;
}

int uniquePaths(int m, int n)
{
    int *buf = malloc(sizeof(int)*m*n);
    int ret = uniquePaths_recursion(n, m-1, n-1, buf);
    free(buf);
    return ret;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[算法]力扣刷题-动态规划 - 不同路径 的相关文章

随机推荐

  • RuntimeError: cublas runtime error : resource allocation failed at

    root bsyocr server train tail trainall210722 6 log txt File home server train pytorch pretrained modeling py line 300 in
  • Nginx的安装(实践记录)

    1 安装nginx需要系统中有gcc环境 先查看本机是否安装gcc gcc version 如果没有就需要安装 gcc gcc c gcc g gcc gnat gcc java gcc objc libgcj libgcj devel l
  • C/C++ 杨辉三角形

    题目描述 还记得中学时候学过的杨辉三角形吗 具体的定义这里不再描述 你可以参考以下的图形 1 1 1 1 2 1 1 3 3 1 1 4 6 4 1 输入 输入数据包含多个测试实例 每个测试实例的输入只包含一个正整数n 1 lt n lt
  • AJAX学习笔记8 跨域问题及解决方案

    AJAX学习笔记7 AJAX实现省市联动 biubiubiu0706的博客 CSDN博客 跨域 指一个域名的网页去请求另外一个域名资源 比如百度页面去请求京东页面资源 同源与不同源三要素 协议 域名 端口 协议一致 域名一致 端口一致 才算
  • JAVA中的内存分配

    JAVA中的内存分配 栈 方法运行时使用的内存 比如main方法的运行 进入方法栈中执行 堆 存储对象或数组 new来创建的 都存储在堆内存中 方法区 存储可以运行的class文件 本地方法栈 JVM在使用操作系统功能的时候使用 和我们开发
  • 查询、关闭正在运行的Tomcat端口

    查询正在使用的端口 快捷键win R 输入cmd 回车 打开cmd窗口 查看所有的端口进程 请输入netstat ano 查看某个特定端口 输入netstat ano findstr 8089 关闭某个端口进程 输入taskkill f p
  • Javaweb

    一 创建包和类来编译servlet程序 二 编译和运行
  • 如何在老版本浏览器中丝滑地使用JS新特性(ES6)

    如何在老版本浏览器中丝滑地使用JS新特性呢 如何在老版本浏览器中丝滑地使用JS新特性呢 有两种方法可以帮助我们实现 第一种方法就是我们用JS原有的方法 自己去实现JS的新特性 不是说好的丝滑使用新特性吗 就这 哈哈哈 别急 客官留步 我还有
  • spring boot 数据库层

    项目开启 首先设计数据库以及存储表 表的联系 需要存贮的信息 基本表的性质 基本表与中间表 临时表不同 因为它具有如下四个特性 1 原子性 基本表中的字段是不可再分解的 2 原始性 基本表中的记录是原始数据 基础数据 的记录 3 演绎性 由
  • openid和unionid的区别

    openid和unionid的区别 1 微信openid和unionid长度是不一样的 openid 28 unionid 29 2 openid同一用户同一应用唯一 unionid同一用户不同应用唯一 这里的不同应用是指在同一微信开发平台
  • C++学习6

    堆 是存在于某个作用域的一个内存空间 例如 当你调用函数 函数本身会形成一个栈用来放置它所接收的参数 以及返回地址 栈 由操作系统提供的一个全局的内存空间 程序可动态分配 内存管理 生命周期 栈对象 离开堆的作用域 会调用对象的析构函数 内
  • rabbitmq分布式事务解决方案

    发送消息到mq 流程 用户下订单创建订单信息 且创建一条订单冗余信息 status 为 0 发送订单信息到mq 使用ack 消息确认机制 确认消息发送成功修改订单状态为 1 表示消息已发送 启动一个定时任务 排查 订单状态为 0 的订单 发
  • Win2003搭建网站教程

    1 搭建Win2003虚拟机 此过程略 2 开始 管理您的服务器 添加或删除角色 3 下一步 配置您的服务器向导 选择应用程序服务器 IIS asp NET 下一步 完成安装 4 打开 开始 管理工具 Internet信息服务器 IIS 管
  • 使用certbot 生成 Let‘s Encrypt 泛域名ssl证书

    文章目录 一 更新证书报错 二 Let s Encrypt 泛域名ssl证书申请 一 更新证书报错 问题描述 更新SSL证书时报 too many failed authorizations 错误 原因分析 当前要更新的域名一个小时触发失败
  • 扫码支付终结刷脸支付强势掘起

    手机支付将会終结 新的支付方式掘起 新的支付方式对很多人还是很陌生的 这就要很好的推广和布置 现在推出了二代的蜻蜓刷脸设备 向商户销售出了舒缓的二代蜻蜓刷脸支付设备 超市 快餐厅 自动贩卖机都已经实现商业直播 相信很快在每个城市 都会发现这
  • 快速排序详解

    近些天来 由于需要找工作 特将数据机构与算法中的快速排序温习总结了一下 希望对于大家学习有所帮助 首先 快速排序的基本思想是基于分治的思想 是冒泡排序的改进型 首先在数组中选择一个基准点 该基准点的选取可能影响快速排序的效率 后面讲解选取的
  • Git提交代码的两种方式

    一 Git Bash提交方式 在电脑桌面鼠标右键点击一下 然后点击Git Bash Here 开始输入命令 1 首次提交 先输入github gitlab等的用户名和邮箱 git命令 git config global user name
  • 【Altium Designer21】使用小技巧

    1 如何取消原理图的网格以及表头如下图 在Properties Visible Grid可以显示 隐藏网格 Title Block勾选上即显示表头 取消勾选即隐藏表头 图1 图2 图3 2 翻转的快捷键 空格 为90翻转 X 为水平翻转 Y
  • Eclipse 启动异常 找不到Java环境(A Java Runtime Environment....)

    点击启动Eclipse弹出异常消息 解决步骤 1 打开eclipse所在文件夹 2 用记事本打开配置文件 即下图的文件 3 找到java所在文件夹 4 复制路径并粘贴到记事本文件中 5 保存并重启Eclipse 大功告成
  • [算法]力扣刷题-动态规划 - 不同路径

    目录 题目 思路 编码 分析 修改 优化 题目 一个机器人位于一个 m x n 网格的左上角 起始点在下图中标记为 Start 机器人每次只能向下或者向右移动一步 机器人试图达到网格的右下角 在下图中标记为 Finish 问总共有多少条不同