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

news2025/4/5 5:14:44

题目:力扣(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.coloradmin.cn/o/1351720.html

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

相关文章

网络端口(包括TCP端口和UDP端口)的作用、定义、分类,以及在视频监控和流媒体通信中的定义

目 录 一、什么地方会用到网络端口&#xff1f; 二、端口的定义和作用 &#xff08;一&#xff09;TCP协议和UDP协议 &#xff08;二&#xff09;端口的定义 &#xff08;三&#xff09;在TCP/IP体系中&#xff0c;端口(TCP和UDP)的作用 &#xff08;…

Visual Studio 2017 + opencv4.6 + contribute + Cmake(Aruco配置版本)指南

之前配置过一次这个&#xff0c;想起这玩意就难受&#xff0c;贼难配置。由于要用到里面的一个库&#xff0c;不得已再进行配置。看网上的博客是真的难受&#xff0c;这写一块&#xff0c;那里写一块&#xff0c;乱七八糟&#xff0c;配置一顿发现写的都是错的&#xff0c;还得…

leetcode刷题日记:222. Count Complete Tree Nodes(完全二叉树的节点个数)

这一道题&#xff0c;我们可以选择直接进行二叉树的遍历&#xff0c;将所有结点遍历一遍就能得到完全二叉树的结点个数&#xff0c;时间复杂度为O(n)。 代码如下&#xff1a; int countNodes(struct TreeNode* root) {if(rootNULL){return 0;}return countNodes(root->left…

【Linux】socket基础API

目录 1. 创建socket&#xff08;TCP/UDP&#xff0c;客户端服务器&#xff09; 1.1 第一个参数——domain 1.2 第二个参数——type 1.3 第三个参数——protocol 2. 绑定socket地址&#xff08;TCP/UDP&#xff0c;服务器&#xff09; 2.1 字节序及转换函数 2.2 IP地址及…

【数字图像处理技术与应用】2023-2024上图像处理期中-云南农业大学

一、填空题&#xff08;每空2 分&#xff0c;共 30 分&#xff09; 1、图像就是3D 场景在 二维 平面上的影像&#xff0c;根据其存储方式和表现形式&#xff0c;可以将图像分为 模拟 图像和数字图像两大类&#xff1b; 2、在用计算机对数字图像处理中&#xff0c;常用一个 二…

[C#]yolov8-onnx在winform部署手势识别模型

【官方框架地址】 https://github.com/ultralytics/ultralytics.git 【算法介绍】 YOLOv8 是一个 SOTA 模型&#xff0c;它建立在以前 YOLO 版本的成功基础上&#xff0c;并引入了新的功能和改进&#xff0c;以进一步提升性能和灵活性。具体创新包括一个新的骨干网络、一个新…

promise.prototype.finally重写和兼容火狐低版本浏览器

一、finally()方法用于指定不管 Promise 对象最后状态如何&#xff0c;都会执行的操作。该方法是 ES2018 引入标准的 let promise new Promise() promise .then(result > {}) .catch(error > {}) .finally(() > {})finally方法的回调函数不接受任何参数;finally方法…

指令、电流、上下斜坡、颤振频率可调型比例放大器

控制不带电反馈的单或双比例电磁铁的比例阀&#xff0c;如比例泵阀、比例插装阀、比例方向阀、比例压力阀、比例流量阀、比例叠加阀等&#xff1b; 常规比例阀控制电流如650mA、700mA、760mA、830mA、950mA、1.6A、2.5A、3A等; 带数显区显示及当前参数现场可调&#xff0c;如…

php合并数组的几种方式 并简述其特点

目前工作中接触到的PHP数组合并方式主要有三种&#xff1a; 1、操作符 2、array_merge() 3、array_merge_recursive() 它们的区别主要体现在对于相同键名&#xff08;数字键名、字符串键名&#xff09;的处理方式&#xff0c; 一 相同字符串键 <?php$arrFirst [&quo…

键盘数字键打不出来怎么解锁?收藏好这4个简单方法!

“我在使用电脑进行办公时&#xff0c;突然发现我电脑键盘的数字键无法输入&#xff0c;这该怎么办呢&#xff1f;我应该如何解锁呢&#xff1f;请给我出出主意吧&#xff01;” 在日常使用电脑时&#xff0c;很多用户都需要使用键盘输入文字。但有时候部分用户也会遇到键盘数字…

SpringBoot: 通过MyBatis访问ClickHouse

一、ClickHouse中建表&#xff0c;添加数据 二、SpringBoot项目添加mybatis、clickhouse、druid相关依赖 <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.6</version></dependency>…

【Proteus仿真】【Arduino单片机】汽车尾气检测报警系统

文章目录 一、功能简介二、软件设计三、实验现象联系作者 一、功能简介 本项目使用Proteus8仿真Arduino单片机控制器&#xff0c;使用按键、LCD1602液晶、蜂鸣器模块、CO、NOx、HC和PM2.5气体传感器等。 主要功能&#xff1a; 系统运行后&#xff0c;LCD1602显示CO、NOx、HC和…

【算法】和为K的连续子数组

牛客链接&#xff1a;https://www.nowcoder.com/practice/704c8388a82e42e58b7f5751ec943a11?tpId196&&tqId37127&rp1&ru/ta/job-code-total&qru/ta/job-code-total/question-ranking 使用【前缀法】&#xff0c;把所有连续和合索引存进哈希表&#xff0c…

55寸oled透明显示屏售价,受哪些因素影响

55寸OLED透明显示屏的售价受到多个因素的影响&#xff0c;包括以下几个方面&#xff1a; 尺寸和分辨率&#xff1a;OLED透明显示屏的尺寸和分辨率是决定价格的重要因素。较大的尺寸和较高的分辨率会增加制造成本和售价。 技术水平和制造工艺&#xff1a;OLED透明显示屏的技术水…

超高速同步PCI数据采集卡PCI8552A

◆ 输入量程&#xff1a;1000mV ◆ 转换精度&#xff1a;12 位(Bit) ◆ 采样频率(Frequency)&#xff1a;最高 150MHz ◆ 物理通道数&#xff1a;2 通道同步 ◆ 模拟量输入方式&#xff1a;单端模拟输入 ◆ 数据读取方式&#xff1a;DMA方式 ◆ 存储器深度&#xf…

Git - 强制替换覆盖 master 分支解决方案

问题描述 在版本迭代中&#xff0c;通常会保持一个主分支 master&#xff0c;及多个 dev 分支&#xff0c;但是因为 dev 分支的开发周期过长&#xff0c;迭代太多而没有及时维护 master &#xff0c;导致后来发版上线的大部分代码都在 dev 分支上&#xff0c;如果将代码在 mas…

Redis(中)

1、redis的持久化 "Redis 如何将数据写入磁盘"&#xff0c;首先要明白的时候&#xff0c;我们使用的redis的数据保存在内存上的&#xff0c;也就是说&#xff0c;只要我们的电脑关机或者重启服务器&#xff0c;那么在内存中的数据就会消失&#xff0c;所以要想持久化…

【GitHub】ssh: connect to host github.com port 22: Connection refused

本地使用git上传GitHub仓库时发现的一个报错&#xff0c;以为是本机连不上github了&#xff0c;ping过后发现能够正常访问&#xff0c;于是上网找到了一个很完美的解决方案 原因&#xff1a;22端口被占用或被防火墙屏蔽 解决方法&#xff1a;切换GitHub的443端口 1.首先找到…

Rancher 单节点 docker 部署备份与恢复

Rancher 单节点 docker 部署备份与恢复 1. 备份集群 获取 rancher server 容器名&#xff0c;本例为 angry_aryabhata docker ps | grep rancher/rancher6a27b8634c80 rancher/rancher:v2.5.14 xxx angry_aryabhata停止容器 docker stop angry_aryabhata创建备…