剑指Offer题目笔记29(动态规划矩阵路径问题)

news2024/11/28 20:49:45

面试题98:

面试题98

问题:

​ 一个机器人从m x n的格子的左上角出发,它每一步只能向下走或者向右走,计算机器人从左上角到达右下角的路径数量。

解决方案:
  1. 机器人每走一步都有两个选择,要么向下走要么向右走。一个任务需要多个步骤才能完成,每步面临若干选择,这类问题看起来可以用回溯法解决,但由于这个题目只要求计算从左上角到达右下角的路径的数目,并没有要求列出所有的路径,因此这个问题更适合用动态规划解决。
  2. 当i等于0或者j等于0时,机器人位于格子最左边的一列,机器人走到左下角或者右上角只能走直线,故f(0,0)走到f(i,0)或者f(0,j)都是只有一条路径。
  3. 当行号i、列号j都大于0时,机器人有两种方法可以到达坐标为(i,j)的位置。它既可以从坐标为(i-1,j)的位置向下走一步,也可以从坐标为(i,j-1)的位置向右走一步,因此,f(i,j)等于 f(i-1,j)与f(i,j-1)之和。
源代码(递归):
class Solution {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        return dfs(m-1,n-1,dp);
    }

    private int dfs(int i,int j,int[][] dp){
        if(dp[i][j] == 0){
            if(i == 0 || j == 0){
                dp[i][j] = 1;
            }else{
                dp[i][j] = dfs(i-1,j,dp) + dfs(i,j-1,dp);
            }
        }

        return dp[i][j];
    }
}
源代码(迭代):
class Solution {
    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];
        dp[0][0] = 0;

        for(int j = 0;j < n;j++){
            dp[0][j] = 1;
        }

        for(int i = 1;i < m;i++){
            dp[i][0] = 1;
            for(int j = 1;j < n;j++){
                dp[i][j] = dp[i-1][j] + dp[i][j-1];
            }
        }

        return dp[m-1][n-1];
    }
}
优化空间效率思路:

​ 在计算f(i,j)时需要用到f(i-1,j)和f(i,j-1)的值。接下来在计算f(i,j+1)时需要用到f(i-1,j+1)和f(i,j)的值。由于在用f(i-1,j)计算出f(i,j)之后就不再需要f(i-1,j),因此可以只用一个位置来保存f(i-1,j)和f(i,j)的值。

源代码:
class Solution {
    public int uniquePaths(int m, int n) {
        int[] dp = new int[n];
        Arrays.fill(dp,1);

        for(int i = 1;i < m;i++){
            for(int j = 1;j < n;j++){
                dp[j] += dp[j-1];
            }
        }
        

        return dp[n-1];
    }
}

面试题99:

面试题99

问题:

​ 在一个m x n的格子中,每个位置都有一个数字。机器人每步只能向下或向右,计算它从格子左上角到右下角的路径数字之和的最小值。

解决方案:
  1. 机器人每一步都有两种选择,要么向下走,要么向右走,但是题目并没有让我们计算出所有的路径,而是让我们计算路径的最小数字之和,故使用动态规划。
  2. 用函数f(i,j)表示从格子的左上角坐标为(0,0)的位置(用grid[0][0]表示)出发到达坐标为(i,j)的位置(用grid[i][j]表示)的路径的数字之和的最小值。如果格子的大小为m×n,那么f(m-1,n-1)就是问题的解。
  3. 当i等于0或者j等于0时,机器人位于格子最上面的一行,机器人只能向下或者向右,如果它想去左下角或者右上角,那么它只能走直线,f(i,0)就等于0到i的数字之和,f(0,j)就等于0到j的数字之和。
  4. 当行号i、列号j都大于0时,机器人有两种方法可以到达坐标为(i,j)的位置。它既可以从坐标为(i-1,j)的位置向下走一步,也可以从坐标为(i,j-1)的位置向右走一步,因此,f(i,j)等于 f(i-1,j)与f(i,j-1)的最小值加上grid[i][j]。
源代码:
class Solution {
    public int minPathSum(int[][] grid) {
        int len1 = grid.length;
        int len2 = grid[0].length;

        int[][] dp = new int[len1][len2];
        dp[0][0] = grid[0][0];

        for(int j = 1;j < len2;j++){
            dp[0][j] = dp[0][j-1] + grid[0][j];
        }

        for(int i = 1;i < len1;i++){
            dp[i][0] = dp[i-1][0] + grid[i][0];
            for(int j = 1;j < len2;j++){
                dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1]) + grid[i][j];
            }
        }

        return dp[len1-1][len2-1];
    }
}
优化空间效率思路:

​ 在计算f(i,j)时需要f(i-1,j)、f(i,j-1)的值。值得注意的是,f(i-1,j)在完成f(i,j)的计算之后再也用不到了,因此将f(i-1,j)和f(i,j)保存到同一个数组dp的同一个位置“dp[j]”中。而f(i,j-1)在计算f(i,j)之前就已经计算好了。

源代码:
class Solution {
    public int minPathSum(int[][] grid) {
        int len1 = grid.length;
        int len2 = grid[0].length;

        int[] dp = new int[len2];
        dp[0] = grid[0][0];

        for(int j = 1;j < len2;j++){
            dp[j] = dp[j-1] + grid[0][j];
        }

        for(int i = 1;i < len1;i++){
            //注意:这里与上题不一样,因为上题是求路径数目,dp【i】与dp【j】相同都是1,使用上题不需要这个步骤。而这题不同,求的是路径和,故需要进行grid[i][0]的累加操作。
            dp[0] += grid[i][0];
            for(int j = 1;j < len2;j++){
                dp[j] = Math.min(dp[j],dp[j-1]) + grid[i][j];
            }
        }

        return dp[len2-1];
    }
}

面试题100:

面试题100

问题:

​ 在一个由数字组成的三角形中,第1个行有1个数字,第2行有2个数字,以此类推,第n行有n个数字。每步只能前往下一行中相邻的数字,计算从三角形顶部到底部的路径经过的数字之和的最小值。

解决方案:
  1. 如果一个三角形有多行,那么从它的顶部到底部需要多步,而且每步都面临两个选择。但是题目没要求我们写出从三角形顶部到底部的全部路径,而是让我们求三角形顶部到底部的最小路径之和,故使用动态规划解决该问题。
  2. 可以用f(i,j)表示从三角形的顶部出发到达行号和列号分别为i和j(i≥j)的位置时路径数字之和的最小值,同时用T[i][j]表示三角形行号和列号分别为i和j的数字。如果三角形中包含n行数字,那么 f(n-1,j)的最小值就是整个问题的最优解。
  3. 如果j等于0,也就是当前到达某行的第1个数字。由于路径的每步都是前往正下方或右下方的数字,而此时当前位置的左上方没有数字,那么前一步是一定来自它的正上方的数字,因此f(i,0)等于 f(i-1,0)与T[i][0]之和。如果i等于j,也就是当前到达某行的最后一个数字,此时它的正上方没有数字,前一步只能是来自它左上方的数字,因此f(i,i)等于f(i-1,i-1)与T[i][i]之和。
  4. 如果当前行号和列号分别为i和j的位置位于某行的中间,那么前一步既可能是来自它正上方的数字(行号和列号分别为i-1和j),也可能是来自它左上方的数字(行号和列号分别为i-1和j-1),所以 f(i,j)等于f(i-1,j)与f(i-1,j-1)的最小值再加上T[i][j]。
源代码:
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int len = triangle.size();
        int[][] dp = new int[len][len];
        dp[0][0] = triangle.get(0).get(0);

        for(int i = 1;i < len;i++){
            dp[i][0] = dp[i-1][0] + triangle.get(i).get(0);
        }

        for(int i = 1;i < len;i++){
            for(int j = 1;j <= i;j++){
                if(j == i){
                    dp[i][j] = dp[i-1][j-1] + triangle.get(i).get(j);
                }else{
                    dp[i][j] = Math.min(dp[i-1][j],dp[i-1][j-1]) + triangle.get(i).get(j);
                }
            }
        }
        int min = Integer.MAX_VALUE;
        for(int j = 0;j < len;j++){
            min = Math.min(min,dp[len-1][j]);
        }
        return min;
    }
}
优化空间效率思路:
  1. 在计算f(i,j)之前“dp[j]”中保存的是f(i-1,j)的值。在计算f(i,j)时需要f(i-1,j-1)和f(i-1,j)。在计算完 f(i,j)之后能否用f(i,j)的值覆盖保存在“dp[j]”中的f(i-1,j)取决于是否还需要f(i-1,j)的值。
  2. 如果从左到右计算的话,计算f(i,j)后会覆盖f(i-1,j),但是后面计算f(i,j+1)的时候还需要用到f(i-1,j),由于计算f(i,j)时并不依赖同一行左侧的f(i,j-1),所以我们可以按照从右到左的顺序计算。
源代码:
class Solution {
    public int minimumTotal(List<List<Integer>> triangle) {
        int len = triangle.size();
        int[] dp = new int[len];
        dp[0] = triangle.get(0).get(0);

        for(int i = 1;i < len;i++){
            for(int j = i;j >= 0;j--){
                if(j == 0){
                    dp[j] += triangle.get(i).get(j);
                }else if(j == i){
                    dp[j] = dp[j-1] + triangle.get(i).get(j);
                }else{
                    dp[j] = Math.min(dp[j],dp[j-1]) + triangle.get(i).get(j);
                }
            }
        }

        int min = Integer.MAX_VALUE;
        for(int j = 0;j < len;j++){
            min = Math.min(min,dp[j]);
        }
        return min;
    }
}

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

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

相关文章

curl下载nexus中的jar包

下载并保持原名称 curl -u admin:password -O "http://127.0.0.1:8081/repository/maven-snapshots/com/edgej/edgej-modules-research/1.0-SNAPSHOT/edgej-modules-research-1.0-20240407.090116-1.jar"下载并重命名 curl -u admin:password -o "edgej-modul…

利用Leaflet + React:构建WEBGIS

React是 Facebook 开发的一个开源库&#xff0c;用于构建用户界面。就其本身而言&#xff0c;Leaflet是一个用于将地图发布到网络的JavaScript 库。这两个工具的组合很简单&#xff0c;允许您创建动态网络地图。在本文中&#xff0c;我们将看到这种组合的一些特征以及一些简单的…

【C++】详解vector二维数组的全部操作(超细图例解析!!!)

目录 一、前言 二、 深度理解vector 的二维数组&#xff08;重点&#xff01;&#xff09; 三、vector 二维数组的空间理解&#xff08;重点&#xff01;&#xff09; ✨问题分析 ✨如何合理定制vector的内存空间 四、vector 二维数组的初始化 五、vector 二维数组的 添加…

宝宝眼部健康,斗鸡眼小心防护

引言&#xff1a; 新生儿期间&#xff0c;宝宝的眼睛需要特别关注和呵护&#xff0c;因为眼睛是宝宝感知世界的窗户。斗鸡眼&#xff0c;即眼球表面的角膜上形成的小疙瘩&#xff0c;虽然在新生儿中比较罕见&#xff0c;但家长们仍然需要了解斗鸡眼的相关知识&#xff0c;并采取…

Vue 有哪些主要的指令修饰符

目录 1. 什么是指令修饰符 2. 指令修饰符有哪些 2.1. 按键修饰符 2.2. v-model修饰符 2.3. 事件修饰符 1. 什么是指令修饰符 通过 "." 指明一些指令 后缀&#xff0c;不同 后缀 封装了不同的处理操作 目的&#xff1a;简化代码 2. 指令修饰符有哪些 2.1. 按键…

让chatGPT控制物理设备

作为自动控制行业的工程师&#xff0c;我们也许最关心的是如何使chatGPT 控制物理设备。我发现许多人仍然停留在传统程序设计的思维阶段&#xff0c;比如让大模型编写一段PLC 代码&#xff0c;或者是生成一些信息模型。 其实大模型具备判断与思考的能力&#xff0c;AI …

尚硅谷html5+css3(2)CSS5基本知识

1.网页分为三个部分&#xff1a; 结构&#xff1a;HTML 表现&#xff1a;CSS 行为JavaScript CSS:层叠样式表&#xff0c;网页实际上是一个多层结构&#xff0c;通过CSS可以分别为网页的每一个层来设置样式&#xff0c;最终用户只看最上面的一层&#xff0c;总之&#xff0…

适用于 Windows 10 的 10 大免费数据恢复软件

数据丢失可能是一场噩梦&#xff0c;尤其是在涉及重要文件和文档时。无论是由于意外删除、系统崩溃还是病毒攻击&#xff0c;找到适合 Windows 10 的文件夹恢复软件都可以在恢复丢失的数据方面发挥重要作用。在本指南中&#xff0c;我们将探索适用于 Windows 10 用户的 10 大免…

景区云旅游/视频慢直播方案设计与平台搭建

一、行业背景 经文化和旅游部数据中心测算&#xff0c;今年清明节假期3天全国国内旅游出游1.19亿人次&#xff0c;按可比口径较2019年同期增长11.5%&#xff1b;国内游客出游花费539.5亿元&#xff0c;较2019年同期增长12.7%。踏青赏花和户外徒步成为假期的热门出游主题。随着…

Nifi同步过程中报错create_time字段找不到_实际目标表和源表中没有这个字段---大数据之Nifi工作笔记0066

很奇怪的问题,在使用nifi的时候碰到的,这里是用NIFI,把数据从postgresql中同步到mysql中, 首先postgresql中的源表,中是没有create_time这个字段的,但是同步的过程中报错了. 报错的内容是说,目标表中有个create_time字段,这个字段是必填的,但是传过来的flowfile文件中,的数据没…

Windows命令行关机操作

cmd相关备忘 1. 导语2. Windows本命操作3. 实用命令集合3.1. 一段时间后关机3.2. 立即关机命令3.3. 一段时间后重启3.4. 休眠命令3.5. 取消指令 &#x1f609; 记录一些不常用有的时候很救命的cmd命令 1. 导语 不知道小伙伴们有么有遇到过这样尴尬的时候&#xff0c;电脑的鼠标…

1.网络编程-网络协议

目录 网络编程是什么 网络编程三要素 OSI七层网络模型 TCP/IP五层模型 SSL/TLS 是哪层协议 网络编程是什么 网络编程是计算机科学中的一个重要领域&#xff0c;它涉及到编写能够在网络环境中进行通信的程序。网络编程的核心目标是使不同的设备能够通过网络交换信息&#…

Python爬虫基础篇章(面试常问1)

如今信息技术的发展已经进入“数据”驱动的时代&#xff0c;通过对海量数据的处理&#xff0c;能够产生极大的科研和商业价值。网络爬虫的出现&#xff0c;将网络上的各种数据进行自动汇总&#xff0c;定制化产生需要的数据&#xff0c;是当今时代数据获取的重要来源。网络爬虫…

《Market Insight:中国流程挖掘市场发展洞察(2023)》报告将于4月11日发布

流程挖掘市场虽然项目数量有所增加&#xff0c;但目前的中国市场依旧处于早期阶段。而伴随着生成式AI技术的发展&#xff0c;流程挖掘市场又将迎来的新的变革和机遇&#xff0c;RPA中国在调研中发现&#xff0c;诸多技术供应商在努力地拥抱生成式AI&#xff0c;以便于提升自身产…

3D渲染器原理及Python朴素实现

最近&#xff0c;我发现自己需要为即将进行的项目提供一些来自不同角度的低多边形 3D 模型的低分辨率精灵。 像这样的东西&#xff1a; 获得它们的可能方法包括&#xff1a; 学习一点 Blender在 WebGL 中制作编写我自己的渲染器 我对 Blender 的短暂经历已经让我受到了创伤&…

24 个Intellij IDEA好用插件

24 个Intellij IDEA好用插件 一. 安装插件 Codota 代码智能提示插件 只要打出首字母就能联想出一整条语句&#xff0c;这也太智能了&#xff0c;还显示了每条语句使用频率。 原因是它学习了我的项目代码&#xff0c;总结出了我的代码偏好。 Key Promoter X 快捷键提示插件 …

CCIE-10-IPv6-TS

目录 实验条件网络拓朴 环境配置开始Troubleshooting问题1. R25和R22邻居关系没有建立问题2. 去往R25网络的下一跳地址不存在、不可用问题3. 去往目标网络的下一跳地址不存在、不可用 实验条件 网络拓朴 环境配置 在我的资源里可以下载&#xff08;就在这篇文章的开头也可以下…

深入MyBatis的动态SQL:概念、特性与实例解析

MyBatis 是一个优秀的持久层框架&#xff0c;它支持定制化 SQL、存储过程以及高级映射。 MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。它可以使用简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff0c;即普通的 Java 对象为数据库中的记…

【数据结构与算法】:快速排序和冒泡排序

一&#xff0c;快速排序 快速排序是一种比较复杂的排序算法&#xff0c;它总共有4种实现方式&#xff0c;分别是挖坑法&#xff0c;左右"指针"法&#xff0c;前后"指针"法&#xff0c;以及非递归的快速排序&#xff0c;并且这些算法中也会涉及多种优化措施…

IntelliJ IDEA 2024.1 更新亮点汇总:全面提升开发体验

IntelliJ IDEA 2024.1 更新亮点汇总&#xff1a;全面提升开发体验 文章目录 IntelliJ IDEA 2024.1 更新亮点汇总&#xff1a;全面提升开发体验摘要引言 IntelliJ IDEA 2024.1 的新增功能主要亮点全行代码完成 最终的支持 Java 22 功能新航站楼 贝塔编辑器中的粘滞线 人工智能助…