LeetCode题练习与总结:不同路径--62

一、题目描述

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

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

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

示例 1:

输入:m = 3, n = 7
输出:28

示例 2:

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

示例 3:

输入:m = 7, n = 3
输出:28

示例 4:

输入:m = 3, n = 3
输出:6

提示:

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

二、解题思路

  1. 动态规划的理解:动态规划是一种通过将复杂问题分解为更小的子问题来解决问题的方法。在这个问题中,我们可以将网格划分为更小的子网格,并找出每个子网格到达右下角的不同路径数量。
  2. 状态定义:定义dp[i][j]为从左上角到达网格第i行第j列的不同路径数量。
  3. 状态转移方程:对于每一个位置(i, j),我们可以从上方(i-1, j)或者左方(i, j-1)到达。因此,dp[i][j]的值可以通过dp[i-1][j](上方来的路径数)加上dp[i][j-1](左方来的的路径数)得到。
  4. 初始化:dp[0][j]和dp[i][0]都是1,因为无论在网格的哪一行或哪一列,到达第一个点都只有一种方法。
  5. 计算顺序:按照行和列的顺序计算dp数组,每次计算都依赖于之前计算的结果。
  6. 结果:dp[m-1][n-1]即为所求,即从左上角到右下角的不同路径数量。

三、具体代码

class Solution {
    public int uniquePaths(int m, int n) {
        // 创建一个(m x n)的二维数组用于存储路径数量
        int[][] dp = new int[m][n];

        // 初始化dp数组的第一行和第一列
        for (int i = 0; i < m; i++) {
            dp[i][0] = 1;
        }
        for (int j = 0; j < n; j++) {
            dp[0][j] = 1;
        }

        // 按行按列填充dp数组
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                // 状态转移方程
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }

        // 返回右下角的路径数量
        return dp[m-1][n-1];
    }
}

四、时间复杂度和空间复杂度

1. 时间复杂度
  • 代码中的三层循环结构决定了时间复杂度。
  • 最外层循环遍历了m行,中间层循环遍历了n列,内层循环则是常数时间的操作。
  • 因此,总的操作次数是m乘以n,即O(m * n)。
2. 空间复杂度
  • 代码中创建了一个m乘以n的二维数组dp来存储每个子问题的解。
  • 这个数组的空间需求是O(m * n)。
  • 由于这是算法中唯一的额外空间消耗,所以空间复杂度是O(m * n)。

五、总结知识点

  1. 动态规划(Dynamic Programming): 动态规划是一种算法设计技术,它将一个复杂问题分解为更小的子问题,并存储这些子问题的解,以避免重复计算。这种方法通常用于解决具有重叠子问题和最优子结构特性的问题。

  2. 状态定义: 在动态规划中,我们需要定义状态以及如何通过子问题的解来构建问题的解。在这个问题中,dp[i][j] 表示从网格的左上角到位置 (i, j) 的不同路径数量。

  3. 状态转移方程: 状态转移方程是动态规划中的核心,它定义了如何从一个或多个较小的子问题的解来构造当前问题的解。在这段代码中,状态转移方程是 dp[i][j] = dp[i-1][j] + dp[i][j-1],表示到达当前位置的路径数量是从上方和左方到达的路径数量之和。

  4. 初始化: 在开始动态规划之前,我们需要初始化一些基础情况,这些情况通常是问题的起始点或者边界条件。在这段代码中,我们初始化了网格的第一行和第一列为1,因为从起点到这些位置只有一条路径。

  5. 迭代计算: 通过嵌套循环,我们按行按列地计算 dp 数组中的每个元素。每次计算都依赖于已经计算过的相邻的上方和左方的元素。

  6. 二维数组: 代码中使用了二维数组 dp 来存储每个位置的路径数量。这是一种常见的数据结构,用于存储和处理网格或矩阵相关的问题。

  7. 边界处理: 在动态规划中,处理边界条件是非常重要的。在这段代码中,我们特别处理了网格的第一行和第一列,因为这些位置只能从一个方向到达。

六、优化后的代码

虽然代码的空间复杂度是O(m * n),但实际上我们可以优化到O(n),因为当我们计算dp[i][j]时,只需要前一行dp[i-1][j]和当前行的dp[i][j-1]的值。

这意味着我们只需要一个一维数组来存储当前行的路径数量,从而将空间复杂度从O(m * n)降低到O(n),因为每一行只需要一个长度为n的数组。

class Solution {
    public int uniquePaths(int m, int n) {
        // 创建一个长度为n的一维数组用于存储路径数量
        int[] dp = new int[n];
        
        // 初始化dp数组的第一列
        for (int i = 0; i < n; i++) {
            dp[i] = 1;
        }

        // 按行填充dp数组
        for (int i = 1; i < m; i++) {
            for (int j = 1; j < n; j++) {
                // 状态转移方程,只使用前一行的数据
                dp[j] = dp[j] + dp[j - 1];
            }
        }

        // 返回最后一列的路径数量
        return dp[n - 1];
    }
}

在这个优化后的代码中,我们只使用了一个一维数组dp,其长度为n。

这样,空间复杂度降低到了O(n),而时间复杂度仍然是O(m * n),因为我们需要遍历m行和n列来填充dp数组。

七、优化代码知识点

  1. 动态规划(Dynamic Programming): 动态规划是一种解决问题的方法,它将问题分解为更小的子问题,并通过保存子问题的解来避免重复计算。这种方法通常适用于具有重叠子问题和最优子结构的问题。

  2. 一维数组(1D Array): 为了优化空间复杂度,代码使用了一维数组 dp 而不是二维数组。这个一维数组的长度等于网格的列数 n,因为计算下一个位置的路径数量只需要知道当前位置和前一个位置的路径数量。

  3. 空间复杂度优化: 通过使用一维数组,代码将空间复杂度从 O(m * n) 降低到 O(n)。这是因为在每一步计算中,我们只需要当前行的路径数量,而不是整个网格的路径数量。

  4. 状态转移方程(State Transition Equation): 状态转移方程是动态规划中的核心,它定义了如何从一个或多个较小的子问题的解来构造当前问题的解。在这段代码中,状态转移方程是 dp[j] = dp[j] + dp[j - 1],表示到达某一列的路径数量是当前位置的路径数量加上前一列的路径数量。

  5. 初始化: 在开始动态规划计算之前,需要初始化数组的基础状态。在这段代码中,所有位置的初始路径数量被设置为1,因为从网格的左上角开始,到达第一列的每个位置只有一条路径。

  6. 迭代计算: 通过嵌套循环,代码按行填充 dp 数组。每次计算都依赖于前一行的数据,这是动态规划中常见的自底向上的方法。

  7. 边界处理: 代码中的循环从第二行开始,直到网格的最后一行。这是因为第一行的路径数量已经在初始化阶段设置好了。

  8. 结果获取: 最后,代码返回 dp 数组的最后一个元素,即到达网格右下角的路径数量。由于我们是从左上角到右下角计算路径数量的,所以最终结果存储在数组的最后一个位置。

以上就是解决这个问题的详细步骤,希望能够为各位提供启发和帮助。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/534846.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【教学类-51-01】20240411动物皮毛图片的彩色打印PDF制作(一页两张图片,2个表格)

作品展示 背景需求&#xff1a; 为了便于快速做出A4两份图片的效果&#xff0c;设计以下代码&#xff0c;进行图片的PDF合成打印 代码参考&#xff1a; 【教学类-50-06】20240410“数一数”4类星号图片制作PDF学具-CSDN博客文章浏览阅读531次&#xff0c;点赞8次&#xff0c;收…

第3章 存储系统(2)

3.3 主存储器与CPU连接 3.3.1 连接原理 现代计算机的MAR和MDR都在CPU内部。 (1)主存储器通过数据总线,地址总线,控制总线与CPU连接。 (2)数据传输率数据总线宽度*总线频率。 (4)控制总线(读写线)控制读写操作。 3.3.2 主存的扩展 数据总线宽度等于存储字长 1.位扩展法【增加…

性能优化“万金油”:缓存Cache

1、首次请求数据时,先从缓存中获取,如果没有,则继续向数据库中获取。获取到数据后,将数据保存到缓存中。再次请求数据,一样先从缓存中获取,成功获取,“缓存命中”。多次请求中,命中次数占全部请求次数的比例,叫“命中率”。如果数据源的数据发生变化,而缓存中的数据没…

4.11作业

服务器端 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include<QTcpServer> //服务器端类 #include<QMessageBox> //消息对话框 #include<QTcpSocket> //客户端类 #include<QList> //链表容器QT_BEGIN_NAMESPACE namespace Ui { cla…

【JAVASE】抽象类和接口及其抽象类和接口的区别

✅作者简介&#xff1a;大家好&#xff0c;我是橘橙黄又青&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;再无B&#xff5e;U&#xff5e;G-CSDN博客 目标&#xff1a; 1. 抽象类 2. 接口 3. Object 类 1. &am…

linux中rpm包与deb包的区别及使用

文章目录 1. rpm与deb的区别2. deb软件包的格式和使用2.1 deb软件包命令遵行如下约定2.2 dpkg命令2.3 apt-命令 3. Unix和Linux的区别Reference 1. rpm与deb的区别 有的系统只支持使用rpm包安装&#xff0c;有的只支持deb包安装&#xff0c;混乱安装会导致系统问题。 关于rpm和…

C语言——实践小游戏(贪吃蛇)代码版

大家好久不见&#xff0c;我是残念我回来了&#xff0c;希望在你看完之后&#xff0c;能对你有所帮助&#xff0c;有什么不足请指正&#xff01;共同学习交流 本文由&#xff1a;残念ing原创CSDN首发&#xff0c;如需要转载请通知 个人主页&#xff1a;残念ing-CSDN博客&#x…

Linux网络名称空间的调试方法全面分析

Linux网络名称空间是一种广泛使用的技术&#xff0c;用于隔离网络环境&#xff0c;特别是在容器化和微服务架构中&#x1f4e6;。然而&#xff0c;随着网络名称空间的广泛应用&#xff0c;开发者和系统管理员可能会遇到需要调试网络名称空间配置和性能的情况&#x1f50d;。本文…

智能驾驶的关键技术:自主泊车轨迹规划

智能驾驶的关键技术&#xff1a;自主泊车轨迹规划 搭载先进的车载传感器、控制器、执行器等装置&#xff0c;具备复杂环境感知、智能化决策等功能的车辆&#xff0c;我们称之其为智能车。智能车的车载决策规划模块用于生成车辆的行驶行为&#xff0c;直接体现车辆行驶的智慧水…

【Tars-go】腾讯微服务框架学习使用01--初始化服务

1 初始INIT-Demo运行 按照官网描述 go get 安装框架依赖 # < go 1.16 go get -u github.com/TarsCloud/TarsGo/tars/tools/tarsgo go get -u github.com/TarsCloud/TarsGo/tars/tools/tars2go # > go 1.16 go install github.com/TarsCloud/TarsGo/tars/tools/tarsgolat…

【网安小白成长之路】6.pkachu、sql-lbas、upload-lbas靶场搭建

&#x1f42e;博主syst1m 带你 acquire knowledge&#xff01; ✨博客首页——syst1m的博客&#x1f498; &#x1f51e; 《网安小白成长之路(我要变成大佬&#x1f60e;&#xff01;&#xff01;)》真实小白学习历程&#xff0c;手把手带你一起从入门到入狱&#x1f6ad; &…

python---3--sort、lambdalen(list1)、sorted_numbers = sorted(numbers)、list.sort()

学习目标&#xff1a; lambda len(list1) sorted_numbers sorted(numbers)list.sort() 目录 学习目标&#xff1a; 学习内容&#xff1a; 匿名函数 lambda表达式 lambda [参数]: 函数 不需要return len(list1) sorted_numbers sorted(numbers) list.sort(keyNone, r…

进程通信(管道)

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 前言 两个进程直接可以进行数据的直接传递吗&#xff1f;答案显然是不可以。 为什么&#xff1f; 我们简单概括就是进程具有独立性&#xff0c;如果说有两个进程&#xff0c;第一个进程可以访问第二个进程的数据&#xff…

ssm“健康早知道”微信小程序

采用技术 ssm“健康早知道”微信小程序的设计与实现~ 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringMVCMyBatis 工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 需求分析 利用ssm、Java、MyEclipse和mysql数据库等知识点&#xff0c;结合相关设…

【CSDN创作优化2】内嵌图片 `<img>` 标签`height`和`width`属性

【CSDN创作优化2】内嵌图片 标签height和width属性 写在最前面<img> 标签简介控制图像尺寸&#xff1a;height和width属性实例为什么要指定height和width注意事项 使用百分比进行响应式设计小结 &#x1f308;你好呀&#xff01;我是 是Yu欸 &#x1f30c; 2024每日百字…

idea 配置各种背景颜色-护眼绿

idea 配置各种背景颜色 1、打开 IDEA 软件&#xff0c;点击左上角的【File】——>【Settings】 2、点击左侧栏中的【Editor】——>【Color Scheme】选项&#xff0c;点击右侧的【scheme】下拉选择你想要的颜色方案。 3、背景色设置护眼绿或其他特定颜色的背景&#xf…

scratch绘制五边形花朵 2024年3月中国电子学会图形化编程 少儿编程 scratch编程等级考试三级真题和答案解析

目录 scratch绘制五边形花朵 一、题目要求 1、准备工作 2、功能实现 二、案例分析 1、角色分析 2、背景分析 3、前期准备 三、解题思路 1、思路分析 2、详细过程 四、程序编写 五、考点分析 六、推荐资料 1、入门基础 2、蓝桥杯比赛 3、考级资料 4、视频课程…

训练营第二十天(二叉树 part06)

训练营第二十天&#xff08;二叉树 part06&#xff09; 654.最大二叉树 力扣题目地址(opens new window) 题目 给定一个不含重复元素的整数数组。一个以此数组构建的最大二叉树定义如下&#xff1a; 二叉树的根是数组中的最大元素。左子树是通过数组中最大值左边部分构造出…

C++模板初阶(个人笔记)

模板初阶 1.泛型编程2.函数模板2.1函数模板的实例化2.2模板参数的匹配规则 3.类模板3.1类模板的实例化 1.泛型编程 泛型编程&#xff1a;编写与类型无关的通用代码&#xff0c;是代码复用的一种手段。模板是泛型编程的基础。 //函数重载 //交换函数的逻辑是一致的&#xff0c…

Java 类加载过程

Java 类加载过程 类的生命周期类的加载过程加载验证准备解析初始化 类的生命周期 类的生命周期&#xff1a; 加载&#xff08;Loading&#xff09;— 验证&#xff08;Verification&#xff09;— 准备&#xff08;Preparation&#xff09;— 解析&#xff08;Resolution&#…