【LeetCode热题100】打卡第21天:最小路径和爬楼梯

news2024/11/26 11:43:17

文章目录

  • 【LeetCode热题100】打卡第21天:最小路径和&爬楼梯
    • ⛅前言
  • 最小路径和
    • 🔒题目
  • 爬楼梯
    • 🔒题目
    • 🔑题解

【LeetCode热题100】打卡第21天:最小路径和&爬楼梯

⛅前言

大家好,我是知识汲取者,欢迎来到我的LeetCode热题100刷题专栏!

精选 100 道力扣(LeetCode)上最热门的题目,适合初识算法与数据结构的新手和想要在短时间内高效提升的人,熟练掌握这 100 道题,你就已经具备了在代码世界通行的基本能力。在此专栏中,我们将会涵盖各种类型的算法题目,包括但不限于数组、链表、树、字典树、图、排序、搜索、动态规划等等,并会提供详细的解题思路以及Java代码实现。如果你也想刷题,不断提升自己,就请加入我们吧!QQ群号:827302436。我们共同监督打卡,一起学习,一起进步。

LeetCode热题100专栏🚀:LeetCode热题100

Gitee地址📁:知识汲取者 (aghp) - Gitee.com

题目来源📢:LeetCode 热题 100 - 学习计划 - 力扣(LeetCode)全球极客挚爱的技术成长平台

PS:作者水平有限,如有错误或描述不当的地方,恳请及时告诉作者,作者将不胜感激

最小路径和

🔒题目

原题链接:64.最小路径和

在这里插入图片描述

  • 解法一:动态规划

    题目分析:①辨别题目的类型。通过阅读并辨别(这个需要学习并做过动态规划这类题型的经验,本体比较好辩别),我们可以发现这是一个典型的动态规划问题,可以使用一个db数组缓存当前节点的最短距离,然后下一个节点就可以复用,而不需要重新去计算。②思考对应的解法。既然我们已经知道,这是一个动态规划问题,剩下的就是推导出转移方程。当前节点的状态,有两个来源,要么从上边来,要么从左边来,因为是最小路径,所以我们使用 M a t h . m i n ( d b [ i − 1 ] [ j ] , d b [ i ] [ j − 1 ] ) Math.min(db[i - 1][j], db[i][j - 1]) Math.min(db[i1][j],db[i][j1])判断当前节点的来源,其次还需要加上当前节点的距离,最终是 d b [ i ] [ j ] = g r i d [ i − 1 ] [ j − 1 ] + M a t h . m i n ( d b [ i − 1 ] [ j ] , d b [ i ] [ j − 1 ] ) db[i][j] = grid[i - 1][j - 1] + Math.min(db[i - 1][j], db[i][j - 1]) db[i][j]=grid[i1][j1]+Math.min(db[i1][j],db[i][j1])。③完善逻辑。通过②可以得到了通用节点的转移方程,但是对于 i==1j==1这两种情况,我们需要单独考虑,因为他们有边界,上边和左边没有元素

    在这里插入图片描述

    /**
     * @author ghp
     * @title 不同路径
     */
    class Solution {
        public int minPathSum(int[][] grid) {
            int m = grid.length;
            int n = grid[0].length;
            int[][] db = new int[m + 1][n + 1];
            for (int i = 1; i <= m; i++) {
                for (int j = 1; j <= n; j++) {
                    if (i == 1 || j == 1) {
                        db[i][j] = grid[i - 1][j - 1] + Math.max(db[i - 1][j], db[i][j - 1]);
                    } else {
                        db[i][j] = grid[i - 1][j - 1] + Math.min(db[i - 1][j], db[i][j - 1]);
                    }
                }
            }
            return db[m][n];
        }
    }
    

    复杂度分析

    时间复杂度: O ( m ∗ n ) O(m*n) O(mn)

    空间复杂度: O ( m ∗ n ) O(m*n) O(mn)

  • 解法二:DFS+记忆搜索

    首先最短路径问题,肯定是可以使用DFS和BFS的,但是直接暴力DFS或BFS是肯定行不通的,这里需要使用记忆搜搜。所谓的记忆搜索很简单,就是在搜索的过程中缓存当前搜索的结果,这样就能减少很多重复性的搜索,从而大大提高搜索效率

    import java.util.Arrays;
    
    /**
     * @author ghp
     * @title 不同路径
     */
    class Solution {
        public int minPathSum(int[][] grid) {
            int m = grid.length;
            int n = grid[0].length;
            int[][] path = new int[m][n];
            // 初始化path数组
            for (int i = 0; i < path.length; i++) {
                Arrays.fill(path[i], -1);
            }
            path[m - 1][n - 1] = grid[m - 1][n - 1];
            return dfs(grid, path, 0, 0);
        }
    
        /**
         * 深度搜索
         *
         * @param grid 待搜索的图
         * @param path 用于记录当前每次搜索的最短路径
         * @param r    行
         * @param c    列
         * @return (0,0)到 (m-1,n-1) 的最短路径
         */
        private int dfs(int[][] grid, int[][] path, int r, int c) {
            if (r >= grid.length || c >= grid[0].length) {
                // 越界
                return Integer.MAX_VALUE;
            }
            if (path[r][c] != -1) {
                // 该点已经走过,直接返回当前点到达终点的最短路径
                return path[r][c];
            }
            // 往下
            int down = dfs(grid, path, r + 1, c);
            // 往右
            int right = dfs(grid, path, r, c + 1);
            // 记录当前节点到达终点的最短路径(核心步骤)
            path[r][c] = grid[r][c] + Math.min(right, down);
            return path[r][c];
        }
    }
    

    复杂度分析

    时间复杂度: O ( m ∗ n ) O(m*n) O(mn)

    空间复杂度: O ( m ∗ n ) O(m*n) O(mn)

  • 解法三:BFS+记忆搜索

    import java.util.Arrays;
    import java.util.LinkedList;
    import java.util.Queue;
    
    /**
     * @author ghp
     * @title 不同路径
     */
    class Solution {
        public int minPathSum(int[][] grid) {
            int[][] path = new int[grid.length][grid[0].length];
            // 初始化记忆数组
            for (int[] row : path) {
                Arrays.fill(row, -1);
            }
            path[0][0] = grid[0][0];
            return bfs(path, grid);
        }
    
        private static int bfs(int[][] path, int[][] grid) {
            int m = grid.length;
            int n = grid[0].length;
            Queue<int[]> queue = new LinkedList<>();
            queue.offer(new int[]{0, 0}); // 出发点
            // 方向向量,向左,向下
            int[][] dirs = {{0, 1}, {1, 0}};
            // 开始进行广度搜索
            while (!queue.isEmpty()) {
                int[] curr = queue.poll();
                int x = curr[0];
                int y = curr[1];
                // 遍历向左和向下的点
                for (int[] dir : dirs) {
                    int dx = x + dir[0];
                    int dy = y + dir[1];
                    if (dx >= 0 && dx < m && dy >= 0 && dy < n) {
                        // 当前没有发生越界
                        if (path[dx][dy] == -1 || path[dx][dy] > path[x][y] + grid[dx][dy]) {
                            // 当前点没有被遍历 或 当前路径长度比之前路径更短,都需要更新最短路径
                            path[dx][dy] = path[x][y] + grid[dx][dy];
                            // 将当前所在坐标加入到队列中,方便遍历下一个节点
                            queue.offer(new int[]{dx, dy});
                        }
                    }
                }
            }
            return path[m - 1][n - 1];
        }
    }
    

    复杂度分析

    时间复杂度: O ( m ∗ n ) O(m*n) O(mn)

    空间复杂度: O ( m ∗ n ) O(m*n) O(mn)


PS:通过提交检测,可以发现虽然三者的时间复杂度和空间复杂度都是一样的,但是时间上和空间上最优的是动态规划,其次是DFS,最好才是BFS。实现起来最复杂的是BFS,其次是DFS,最后才是动态规划,所以综上所述,本题的最优解是动态规划,LeetCode官方也只提供了动态规划的题解(●ˇ∀ˇ●)

爬楼梯

🔒题目

原题链接:70.爬楼梯

在这里插入图片描述

🔑题解

  • 解法一:暴力DFS(示例数据为44时时间超限)

    在这里插入图片描述

    /**
     * @author ghp
     * @title 爬楼梯
     */
    class Solution {
        private int count = 0;
        public int climbStairs(int n) {
            dfs(n, 0);
            return count;
        }
    
        private void dfs(int n, int path) {
            if (path == n){
                count++;
                return;
            }
            if (path > n){
                return;
            }
            for (int i = 1; i <= 2; i++) {
                dfs(n, path+i);
            }
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( 2 n ) O(2^n) O(2n)
    • 空间复杂度: O ( n ) O(n) O(n)

    代码优化:DFS+记忆搜索

    可以使用记忆化搜索来优化这段代码,避免重复计算。具体实现如下:

    1. 创建一个记忆数组 memo,将每个位置初始化为 -1,表示没有计算过。
    2. 在 dfs 函数中,首先判断 memo 数组中当前状态是否计算过,若已计算过则直接返回对应的值。
    3. 如果 memo 数组中当前状态未计算过,则进行正常的搜索,并在结束搜索后将结果保存到 memo 数组中。
    4. 最后返回结果即可。

    主要思想,因为DFS搜索的结果是一颗二叉树,二叉树具有对称性,当我们在左边搜索过结果,右侧搜索到同样的结果时,可以直接不需要计算,直接使用之前的计算结果

    在这里插入图片描述

    import java.util.Arrays;
    
    /**
     * @author ghp
     * @title 爬楼梯
     */
    class Solution {
        private int count = 0; // 记录可达的路径条数
        private int[] memo; // 记录当前节点可达的路径条数
    
        public int climbStairs(int n) {
            memo = new int[n + 1];
            Arrays.fill(memo, -1);
            dfs(n, 0);
            return count;
        }
    
        private void dfs(int n, int path) {
            if (path == n) {
                // 当前路径符合,路径条数+1
                count++;
                return;
            }
            if (path > n) {
                // 已经到底了,无法继续往下遍历
                return;
            }
            if (memo[path] != -1) {
                // 当前节点被遍历过,则不需要继续往下遍历
                count += memo[path];
                return;
            }
            // 遍历当前节点下的左右子树
            for (int i = 1; i <= 2; i++) {
                dfs(n, path + i);
            }
            // 将当前节点可达的路径总数保存到 memo 数组中
            memo[path] = count;
        }
    }
    

    复杂度分析:

    时间复杂度和空间复杂度和之前是一样的,通过存储每次搜索的状态,我们可以减少很多重复的搜索

  • 解法二:动态规划

    每一个阶梯都有两个状态,要么来自上一个(走一步),要么来自上上一个(走两步),所以我们可以得到状态转移方程: f ( x ) = f ( x − 1 ) + f ( x − 2 ) f(x)=f(x-1)+f(x-2) f(x)=f(x1)+f(x2),通过枚举,可以发现 f ( 1 ) = 1 , f ( 2 ) = 2 , f ( 3 ) = 3 , f ( 4 ) = 5... f(1)=1,f(2)=2,f(3)=3,f(4)=5... f(1)=1,f(2)=2,f(3)=3,f(4)=5...显然,这是一个斐波那契数列!

    class Solution {
        public int climbStairs(int n) {
            int p = 0, q = 0, r = 1;
            for (int i = 1; i <= n; ++i) {
                p = q; 
                q = r; 
                r = p + q;
            }
            return r;
        }
    }
    

    复杂度分析:

    • 时间复杂度: O ( n ) O(n) O(n)
    • 空间复杂度: O ( 1 ) O(1) O(1)
  • 解法三:公式法

    在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

深入了解RTMP协议:实时传输的利器

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;不想…

【环境配置】MATLAB r2022b+opencv3.4.1+mexopencv3.4.1+Windows 11 配置

参考链接&#xff1a; mexopencv官方文档&#xff1a;介绍了全部流程 补充官方文档Configure OpenCV出现的问题&#xff1a;直到Configure后没有红色&#xff0c;再点击Generate 最新Opencv 与 VC 的版本对应关系&#xff08;2023-04-08&#xff09; MATLAB支持和兼容的编译器 …

大学物理(上)-期末知识点结合习题复习(5)——刚体力学-转动惯量、力矩、线密度 面密度 体密度、平行轴定理和垂直轴定理、角动量定理和角动量守恒定律

目录 刚体的定轴转动 题1 题目描述 题解 题2 题解 题3 题目描述 题解 题4 题目描述 题解 题5 题目描述 题解 角动量定理和角动量守恒定律 刚体的定轴转动 1.转动动能 由&#xff0c;得 表示质量 表示质量分布点 2.转动惯量 为刚体对给定轴的转动惯量&…

原生小程序 微信小程序 使用ucharts

一般是uni-app项目使用ucharts在原生微信小程序也是可以使用。 方法&#xff1a; ## 使用说明 请将项目根目录 微信小程序/uCharts-组件/qiun-wx-ucharts/src 下全部文件复制到指定位置&#xff0c;例如该项目的components/qiun-wx-uchart目录下&#xff0c;然后在页面的json配…

2023互联网寒冬之下Java程序员要怎么应对才能找到工作

在互联网寒冬下&#xff0c;Java程序员需要做好哪些方面的准备&#xff0c;才能够更好地找到工作呢&#xff1f; 1.关注用人单位的招聘需求&#xff1b;Java程序员应该关注用人单位的招聘信息&#xff0c;并针对不同的招聘岗位进行精准的自我定位和筛选。在面试前可以充分了解…

Gin框架原生方式切割日志,Go语言原生日志切割

目录 摘要 痛点 正文 1.分析 io.Writer 接口 2.实现 io.Writer 接口 3.将它作为原生输出 4.将它作为 Gin 框架的输出 摘要 自定义一个日志输出&#xff0c;将go语言和gin框架的日志自动按天拆分。本文通过实现io.Writer接口的方式&#xff0c;替换原生和gin框架的默认W…

DAY21——二叉树part7

1.二叉搜索树最小差值 二叉搜索树中序遍历得到有序的数字序列&#xff0c;记录前一个节点 class Solution {TreeNode pre;int result Integer.MAX_VALUE;public int getMinimumDifference(TreeNode root) {if(rootnull)return 0;traversal(root);return result;}private voi…

【Java算法题】剑指offer_数据结构之03队列栈

前言 刷题链接&#xff1a; https://www.nowcoder.com/exam/oj/ta?page2&tpId13&type265 原定于5.30写完队列&栈&#xff0c;超时了14天&#xff08;2周&#xff09;&#xff0c;于6.13完成。 刷算法题到现在得出一个心得&#xff0c;万事开头难。没刷之前总觉得…

django的项目结构介绍

目录 django的安装django项目创建django项目启动django项目关闭django项目个个文件分析核心文件 manage.py项目内部文件start01/start01setting文件的讲解 django的安装 pip install django检测安装后的版本 python -m django --versiondjango项目创建 django安装以后 会自动…

面向对象的多态

7. 面向对象特征三&#xff1a;多态性 概念 多态是面向对象程序设计&#xff08;OOP&#xff09;的一个重要特征&#xff0c;指同一个实体同时具有多种形式&#xff0c;即同一个对象&#xff0c;在不同时刻&#xff0c;代表的对象不一样&#xff0c;指的是对象的多种形态。 变…

作为软件工程师对Docker的认知和看法

文章目录 前言一、Docker是什么&#xff1f;二、Docker和Virtual Machine的区别三、Docker架构1. Client2. Docker Host3. Registry 四、Docker在实际应用中的好处配置环境网络和卷更新管理 总结 前言 两年前我还没有接触过Docker&#xff0c;也不理解Docker在自动化工程应用中…

k8s如何使用ceph rbd块存储(静态供给、存储类动态供给)

目录 前言安装ceph集群ceph集群创建rbd块存储rbd块存储不支持ReadWriteManyk8s配置rbd块存储&#xff08;静态供给&#xff09;创建secret创建pv创建pvck8s节点安装客户端依赖包部署pod查看pod验证是否持久化 k8s配置rbd块存储&#xff08;动态供给&#xff09;查看官网ceph集群…

mysql 最常用的一些语句

1 数据库相关操作 CREATE DATABASE IF NOT EXISTS daily-test DEFAULT CHARSET utf8 COLLATE utf8_general_ci&#xff1b; drop database daily_test; use daily_test 具体操作如下图上所示&#xff1a; 2 mysql常用数据类型 MySQL 数据类型 | 菜鸟教程 3 数据库表相关操作…

Stimulsoft Forms.WEB 23.2.6 Crack

Stimulsoft Forms.WEB 发布 创建、编辑、填写、发布和分发交互式表单。 2023 年 6 月 13 日 - 9:34 新产品 特征 您可以为几乎任何目的创建任何类型的文档 - 发票和支票、各种调查问卷和工作表、订单、简历等等。用户收到可编辑的 PDF 格式的完成模板&#xff0c;可以在任何现代…

英伟达开发板学习系列---国产【Jetson Xavier NX】系统安装及基础配置

1. 前言 最近新买了Jetson Xavier NX, 和之前英伟达原厂的NX的区别在于国产Jetson Xavier NX 是核心板使用的是英伟达的&#xff0c;扩展板是国产的。具体详情如下&#xff1a; 官方NX和国产NX详情区别 2. 设置系统从固态硬盘启动 官方NX出厂是直接将SD卡&#xff08;64/12…

Redis GEO地理位置信息的应用

Redis GEO地理位置信息的应用 Redis GEO概述应用场景Redis GEO命令GEO命令演示 Redis GEO实现附近人的功能基础类API接口接口实现执行测试 Redis GEO 概述 Redis的GEO操作是一种基于地理位置信息进行操作的功能。它使用经度和纬度坐标来表示地理位置&#xff0c;支持存储地理位…

湖南大学CS-2020期末考试解析

【特别注意】 答案来源于@wolf 是我在备考时自己做的,仅供参考,若有不同的地方欢迎讨论。 【试卷评析】 有必要一做。 【试卷与答案】 1.简答题(10 分) 假设一个基于 IEEE 浮点格式的 10 位浮点表示,有 1 个符号位,4 个阶码位(k=4)和 5 个 尾数位(n=5)。 (…

湖南大学CS-2018期末考试解析

【特别注意】 答案来源于@wolf 是我在备考时自己做的,仅供参考,若有不同的地方欢迎讨论。 【试卷评析】 有必要一做。 【试卷与答案】 一、选择题(每题 2 分,共 10 分) 1. 0x12345678 存放在采用小端存储的机器上,地址为 0x100 到

湖南大学CS-2017(另一张)期末考试解析

【特别注意】 答案来源于wolf 是我在备考时自己做的&#xff0c;仅供参考&#xff0c;若有不同的地方欢迎讨论。 【试卷评析】 有必要一做。 【试卷与答案】 由于这张试卷没有电子版&#xff0c;我就直接拍我自己的作答了

八大排序算法之归并排序(递归实现+非递归实现)

目录 一.归并排序的基本思想 归并排序算法思想(排升序为例) 二.两个有序子序列(同一个数组中)的归并(排升序) 两个有序序列归并操作代码: 三.归并排序的递归实现 递归归并排序的实现:(后序遍历递归) 递归函数抽象分析: 四.非递归归并排序的实现 1.非递归归并排序算法…