算法29:不同路径问题(力扣62和63题)--针对算法28进行扩展

题目:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

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

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

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

分析:

假设为3行2列的二维数组

1. 向右---向下---向下

2. 向下---向下---向右

3. 向下--向右---向下

可以推导

1. 一直向右和一直向下,每种走法只有1种走法,没有其他可以旋转的空间。因此

11
12
1

2 、那么到达dp[1][1] 的走法就是 1 + 1 = 2;

3. 那么到达右下角dp[2][1] 就是 2 + 1 = 3; 即3种走法

分析2:

假设有3行7列

1. 按行走,只有1种走法

2、按列走,只有一种走法,可得

1111111
1
1

那么dp[1][1] 就是 dp[0][1] + dp[1][0] 即 1+ 1 = 2;依次类推可得

1111111
1234567
1

第三行还是按照这种方式推导,可得

1111111
1234567
13610152128

因此,针对3行7列的二维数组,可得28种走法

代码实现:

public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];

        //第一行都为1
        for (int col = 0; col < n; col++) {
            dp[0][col] = 1;
        }

        //第一列都为1
        for (int row = 0; row < m; row++) {
            dp[row][0] = 1;
        }

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

        return dp[m-1][n-1];
    }

还是一样的问题,以上代码的时间复杂度为O(m*n), 空间复杂度也为O(m*n). 如果100行100列的二维数组,将浪费100*100的空间复杂度。

空间压缩进行优化:

 public int uniquePaths2(int m, int n) {

        int[] dp = new int[n];
        //第一行都为1
        for (int col = 0; col < n; col++) {
            dp[col] = 1;
        }


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

        return dp[n -1];
    }

完整代码:

package code03.动态规划_07.lesson4;

//力扣62题
// https://leetcode.cn/problems/unique-paths/description/
public class DiffPathSum_02 {

    public int uniquePaths(int m, int n) {
        int[][] dp = new int[m][n];

        //第一行都为1
        for (int col = 0; col < n; col++) {
            dp[0][col] = 1;
        }

        //第一列都为1
        for (int row = 0; row < m; row++) {
            dp[row][0] = 1;
        }

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

        return dp[m-1][n-1];
    }

    public int uniquePaths2(int m, int n) {

        int[] dp = new int[n];
        //第一行都为1
        for (int col = 0; col < n; col++) {
            dp[col] = 1;
        }


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

        return dp[n -1];
    }
}

力扣测试通过:

题目:力扣63题: 力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台

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

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

现在考虑网格中有障碍物。那么从左上角到右下角将会有多少条不同的路径?

网格中的障碍物和空位置分别用 1 和 0 来表示。

分析:

1. 这一题其实跟上面一体解法相同,唯一的不同之处是有障碍物。

2. 第一行和第一列遇到障碍物,那么后面的路都走不通而已

3. 后面的推导,当前方格为障碍物,设置0代表走不通;如果不为0,则按照原有逻辑进行推导即可

完整代码:

package code03.动态规划_07.lesson4;

//力扣63题
// https://leetcode.cn/problems/unique-paths-ii/description/
public class DiffPathSum_03 {


    //时间复杂度 O(m*n), 空间复杂度 O(m*n)
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;

        //obstacleGrid[0][0] == 1 代表左上角第一个就是障碍物
        //obstacleGrid[m-1][n-1] == 1 代表右下角最后一个是障碍物
        if (obstacleGrid == null
                || obstacleGrid.length == 0
                || obstacleGrid[0][0] == 1
                || obstacleGrid[m-1][n-1] == 1) {
            return 0;
        }

        int[][] dp = new int[m][n];

        //处理第一行
        dp[0][0] = 1;
        for (int col = 1; col < n; col++) {
            //如果当前列为1, 或者前一列为0. 代表遇到障碍物。后面路走不通,全部变为0
            if (obstacleGrid[0][col] == 1 || dp[0][col -1] == 0) {
                dp[0][col] = 0;
            } else {
                //第一行只有1条路
                dp[0][col] = 1;
            }
        }

        //处理第一列
        for (int row = 1; row < m; row++) {
            //如果当前列为1, 或者上一列为0. 代表遇到障碍物。后面路走不通,全部变为0
            if (obstacleGrid[row][0] == 1 || dp[row-1][0] == 0) {
                dp[row][0] = 0;
            } else {
                //第一行只有1条路
                dp[row][0] = 1;
            }
        }

        for (int row = 1; row < m; row++) {
            for(int col = 1; col < n; col++) {
                //如果当前列有障碍物,此条路走不通。当前列的值变为0
                //否则,按照原有的逻辑进行计算
                dp[row][col] = obstacleGrid[row][col] == 1 ? 0: dp[row][col - 1] + dp[row - 1][col];
            }
        }

        return dp[m-1][n-1];
    }

    //空间压缩
    //时间复杂度 O(m*n), 空间复杂度 O(n)
    public int uniquePathsWithObstacles2(int[][] obstacleGrid) {

        int m = obstacleGrid.length;
        int n = obstacleGrid[0].length;

        //obstacleGrid[0][0] == 1 代表左上角第一个就是障碍物
        //obstacleGrid[m-1][n-1] == 1 代表右下角最后一个是障碍物
        if (obstacleGrid == null
                || obstacleGrid.length == 0
                || obstacleGrid[0][0] == 1
                || obstacleGrid[m-1][n-1] == 1) {
            return 0;
        }

        int[] dp = new int[n];
        //处理第一行
        dp[0] = 1;
        for (int col = 1; col < n; col++) {
            //如果当前列为1, 或者前一列为0. 代表遇到障碍物。后面路走不通,全部变为0
            if (obstacleGrid[0][col] == 1 || dp[col -1] == 0) {
                dp[col] = 0;
            } else {
                //第一行只有1条路
                dp[col] = 1;
            }
        }

        for (int row = 1; row < m; row++) {
            //当前列为障碍物或者上一列为障碍物,都走不通。
            dp[0] =  (obstacleGrid[row][0] == 1 || dp[0] == 0) ? 0 : 1;

            for(int col = 1; col < n; col++) {
                //如果当前列有障碍物,此条路走不通。当前列的值变为0
                //否则,按照原有的逻辑进行计算
                dp[col] = obstacleGrid[row][col] == 1 ? 0 : dp[col -1] + dp[col];
            }
        }

        return dp[n-1];
    }

    public static void main(String[] args) {
        DiffPathSum_03 test = new DiffPathSum_03();

        int[][] arr = {
                {0, 0, 0},
                {0, 1, 0},
                {0, 0, 0}
        };

        System.out.println(test.uniquePathsWithObstacles2(arr));
    }
}

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

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

相关文章

L1-085:试试手气

我们知道一个骰子有 6 个面&#xff0c;分别刻了 1 到 6 个点。下面给你 6 个骰子的初始状态&#xff0c;即它们朝上一面的点数&#xff0c;让你一把抓起摇出另一套结果。假设你摇骰子的手段特别精妙&#xff0c;每次摇出的结果都满足以下两个条件&#xff1a; 1、每个骰子摇出…

设计模式② :交给子类

文章目录 一、前言二、Template Method 模式1. 介绍2. 应用3. 总结 三、Factory Method 模式1. 介绍2. 应用3. 总结 参考内容 一、前言 有时候不想动脑子&#xff0c;就懒得看源码又不像浪费时间所以会看看书&#xff0c;但是又记不住&#xff0c;所以决定开始写"抄书&qu…

C#之反编译之路(一)

本文将介绍微软反编译神器dnSpy的使用方法 c#反编译之路(一) dnSpy.exe区分64位和32位,所以32位的程序,就用32位的反编译工具打开,64位的程序,就用64位的反编译工具打开(个人觉得32位的程序偏多,如果不知道是32位还是64位,就先用32位的打开试试) 目前只接触到wpf和winform的桌…

算法每日一题:在链表中插入最大公约数 | 链表 | 最大公约数

hello&#xff0c;大家好&#xff0c;我是星恒 今天的题目是有关链表和最大公约数的题目&#xff0c;比较简单&#xff0c;核心在于求解最大公约数&#xff0c;我们题解中使用辗转相除法来求解&#xff0c;然后我们会在最后给大家拓展一下求解最大公约数的四个方法&#xff0c;…

码云Gitee复制 GitHub 项目

码云提供了直接复制 GitHub 项目的功能&#xff0c;方便我们做项目的迁移和下载。 1.新建仓库 2.导入仓库 3.强制同步 如果 GitHub 项目更新了以后&#xff0c;在码云项目端可以手动重新同步&#xff0c;进行更新&#xff01;

odoo16 连接postgresql错误

odoo16 连接postgresql错误 odoo16 用odoo15的环境出错&#xff0c;看到是psycopg2.OperationalError分析是postgresql版本问题&#xff0c;安装了13版本&#xff0c;还是出错&#xff0c;多版本共存问题如下&#xff1a; Traceback (most recent call last):File "D:\o…

数一下 1到 100 的所有整数中出现多少个数字9并输出这些数字

分析&#xff1a; 我们知道 1-100的整数 i 中&#xff0c;9会出现在十位和个位上&#xff0c;数9出现的次数可以通过以下来实现&#xff1a; 个位是9 // i % 10得到整数 i 个位上的数十位是9 // i / 10得到整数 i 除了个位数的数字 这也是做这道题之后&#xff0c;我们需要…

MySQL基础笔记(5)DCL数据控制语句

数据控制语句&#xff0c;用来管理数据库用户、控制数据库的访问权限~ 目录 一.用户管理 1.查询用户 2.创建用户 3.修改用户密码 4.删除用户 二.权限管理 1.查询权限 2.授予权限 3.撤销权限 一.用户管理 1.查询用户 use MySQL; select * from user; 2.创建用户 crea…

MySQL——视图

目录 一.视图介绍 二.基本使用 三.视图规则和限制 一.视图介绍 视图是一个虚拟表&#xff0c;其内容由查询定义。同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。视图的数据变化会影响到基表&#xff0c;基表的数据变化也会影响到视图。 二.基本使用 创…

深入理解MySQL索引底层数据结构

听课问题(听完课自己查资料) 什么是二叉树 二叉树是怎么存储数据的一个链表是一个集合的数据结构 List是怎么便利找到指定下标元素为什么会快&#xff1f;什么是红黑树 红黑树是怎么存储数据的什么是B TREE 是怎么存储数据的什么是BTREE 是怎么存储数据的 疑惑答案 a. 二叉树…

用通俗易懂的方式讲解:结合检索和重排序模型,改善大模型 RAG 效果明显

最近出现了在构建聊天机器人方面的应用浪潮&#xff0c;这主要得益于LlamaIndex 和 LangChain 这样的框架。许多这类应用都采用了用于检索增强生成&#xff08;RAG&#xff09;的标准技术栈&#xff0c;其中包括以下关键步骤&#xff1a; 向量存储库&#xff1a; 使用向量存储库…

状态机(有限状态机(Finite State Machine, FSM)、推进自动机(Pushdown Automata)、并发状态机、分层状态机)

文章目录 状态机&#xff08;State Machine&#xff09;定义与组成定义组成状态&#xff08;States&#xff09;事件&#xff08;Events&#xff09;转换&#xff08;Transitions&#xff09;初始状态&#xff08;Initial State&#xff09; 状态机的类型有限状态机&#xff08…

网络调试 UDP1,开发板用静态地址-入门6

https://www.bilibili.com/video/BV1zx411d7eC?p11&vd_source109fb20ee1f39e5212cd7a443a0286c5 1, 开发板连接路由器 1.1&#xff0c;烧录无OS UDP例程 1.2&#xff0c;Mini USB连接电脑 1.3&#xff0c;开发板LAN接口连接路由器 2. Ping开发板与电脑之间通信* 2.1 根据…

某金属加工公司的核心人才激励体系搭建项目纪实

【客户行业】金属加工行业 【问题类型】薪酬体系/激励体系 【客户背景】 某大型金属加工企业位于河北地区&#xff0c;成立于2000年&#xff0c;隶属于某大型有色金属集团&#xff0c;是一家集科研、开发、生产、销售于一体的国有企业&#xff0c;人员达到1000人。经过多年…

【Redis端口】通过修改端口一个计算机上可以运行两个redis

一个计算机上可以运行多个Redis实例。每个Redis实例都会监听一个特定的端口&#xff0c;所以只要确保每个实例使用的端口不冲突&#xff0c;就可以在同一台计算机上运行多个Redis实例。例如&#xff0c;你可以配置一个Redis实例监听6379端口&#xff0c;另一个Redis实例监听638…

阿里云服务器配置jupyter(新手入门,详细全面)

设置安全组 1.租好服务器后在阿里云服务器平台上打开控制台&#xff08;右上角&#xff09; 2.点开自己的云服务器控制台&#xff0c;在左栏“安全组”部分添加安全规则&#xff0c;点击“管理规则” 单击“手动添加”&#xff0c;将安全组设为如下格式&#xff0c;端口范围…

Java经典框架之Dubbo

Dubbo Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机&#xff0c;Java 仍是企业和开发人员的首选开发平台。 课程内容的介绍 1. Dubbo概述 2. Dubbo基本应用 3…

React基础应用及常用代码

目录 基础知识 babel.config.js js,html,css,Vue,react,angular,nodejs,webpack,less,ES6,commonjs等的关系 ECMAScript 6&#xff08;ES6&#xff09; let、const、var 的区别 Webpack、npm、node关系 props和state区别 通用框架类 ES 6 export React React.Fragm…

【LLM】大型语言模型:2023年完整指南

Figure 1: Search volumes for “large language models” 近几个月来&#xff0c;大型语言模型&#xff08;LLM&#xff09;引起了很大的轰动&#xff08;见图1&#xff09;。这种需求导致了利用语言模型的网站和解决方案的不断开发。ChatGPT在2023年1月创下了用户群增长最快…

thinkphp学习04-控制器定义

控制器&#xff0c;即 controller&#xff0c;控制器文件存放在 controller 目录下&#xff1b; 如果想改变系统默认的控制器文件目录&#xff0c;可以在 config 下 route.php 配置&#xff1a; 将controller修改为controller123&#xff0c;就会报错&#xff0c;说明这个配置…
最新文章