不同路径 II[中等]

news2024/9/21 18:41:55

优质博文:IT-BLOG-CN

一、题目

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

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

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

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

示例 1:
在这里插入图片描述

输入:obstacleGrid = [[0,0,0],[0,1,0],[0,0,0]]
输出:2
解释:3x3网格的正中间有一个障碍物。
从左上角到右下角一共有2条不同的路径:

  1. 向右 -> 向右 -> 向下 -> 向下
  2. 向下 -> 向下 -> 向右 -> 向右

示例 2:
在这里插入图片描述

输入:obstacleGrid = [[0,1],[0,0]]
输出:1

m == obstacleGrid.length
n == obstacleGrid[i].length
1 <= m, n <= 100
obstacleGrid[i][j]01

二、代码

动态规划

我们用 f(i,j) 来表示从坐标 (0,0) 到坐标 (i,j) 的路径总数,u(i,j) 表示坐标 (i,j) 是否可行,如果坐标 (i,j) 有障碍物,u(i,j)=0,否则 u(i,j)=1。

因为「机器人每次只能向下或者向右移动一步」,所以从坐标 (0,0) 到坐标 (i,j) 的路径总数的值只取决于从坐标 (0,0) 到坐标 (i−1,j) 的路径总数和从坐标 (0,0) 到坐标 (i,j−1) 的路径总数,即 f(i,j) 只能通过 f(i−1,j) 和 f(i,j−1) 转移得到。当坐标 (i,j) 本身有障碍的时候,任何路径都到到不了 f(i,j),此时 f(i,j)=0;下面我们来讨论坐标 (i,j) 没有障碍的情况:如果坐标 (i−1,j) 没有障碍,那么就意味着从坐标 (i−1,j) 可以走到 (i,j),即 (i−1,j) 位置对 f(i,j) 的贡献为 f(i−1,j),同理,当坐标 (i,j−1) 没有障碍的时候,(i,j−1) 位置对 f(i,j) 的贡献为 f(i,j−1)。综上所述,我们可以得到这样的动态规划转移方程:

f(i,j)={ 0, u(i,j)=0 }​
f(i,j)={ f(i−1,j)+f(i,j−1), u(i,j) != 0 }

很显然我们可以给出一个时间复杂度 O(nm) 并且空间复杂度也是 O(nm) 的实现,由于这里 f(i,j) 只与 f(i−1,j) 和 f(i,j−1) 相关,我们可以运用「滚动数组思想」把空间复杂度优化称 O(m)。「滚动数组思想」是一种常见的动态规划优化方法,在我们的题目中已经多次使用到,例如「剑指 Offer 46. 把数字翻译成字符串」、「70. 爬楼梯」等,当我们定义的状态在动态规划的转移方程中只和某几个状态相关的时候,就可以考虑这种优化方法,目的是给空间复杂度「降维」。如果你还不知道什么是「滚动数组思想」,一定要查阅相关资料进行学习哦。

代码中给出了使用「滚动数组思想」优化后的实现。

回顾这道题,其实这类动态规划的题目在题库中也出现过多次,例如「221. 最大正方形」、「1162. 地图分析」等。他们都以二维坐标作为状态,大多数都可以使用滚动数组进行优化。如果我们熟悉这类问题,可以一眼看出这是一个动态规划问题。当我们不熟悉的时候,怎么想到用动态规划来解决这个问题呢?我们需要从问题本身出发,寻找一些有用的信息,例如本题中:(i,j) 位置只能从 (i−1,j) 和 (i,j−1) 走到,这样的条件就是在告诉我们这里转移是 「无后效性」 的,f(i,j) 和任何的 f(i ′,j ′)(i ′>i,j ′>j) 无关。
动态规划的题目分为两大类,一种是求最优解类,典型问题是背包问题,另一种就是计数类,比如这里的统计方案数的问题,它们都存在一定的递推性质。前者的递推性质还有一个名字,叫做 「最优子结构」 ——即当前问题的最优解取决于子问题的最优解,后者类似,当前问题的方案数取决于子问题的方案数。所以在遇到求方案数的问题时,我们可以往动态规划的方向考虑。
通常如果我们察觉到了这两点要素,这个问题八成可以用动态规划来解决。读者可以多多练习,熟能生巧。

class Solution {
    public int uniquePathsWithObstacles(int[][] obstacleGrid) {
        int n = obstacleGrid.length, m = obstacleGrid[0].length;
        int[] f = new int[m];

        f[0] = obstacleGrid[0][0] == 0 ? 1 : 0;
        for (int i = 0; i < n; ++i) {
            for (int j = 0; j < m; ++j) {
                if (obstacleGrid[i][j] == 1) {
                    f[j] = 0;
                    continue;
                }
                if (j - 1 >= 0 && obstacleGrid[i][j - 1] == 0) {
                    f[j] += f[j - 1];
                }
            }
        }
        
        return f[m - 1];
    }
}

时间复杂度: O(nm),其中n为网格的行数,m为网格的列数。我们只需要遍历所有网格一次即可。

空间复杂度: O(m)。利用滚动数组优化,我们可以只用O(m)大小的空间来记录当前行的f值。

个人认为,第二个if里面的判断条件 obstacleGrid[i][j - 1] == 0 是可以优化去掉的。

因为空间压缩后,当前的f[j]由f[j-1] 和 上一轮的f[j]转移:

f[j-1]在上一趟循环中已经更新(如果obstacleGrid[i][j-1] == 1,f[j-1] = 0)

f[j]是上一轮的,也已经更新(如果obstacleGrid[i-1][j]== 1,f[j] = 0)

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

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

相关文章

@[TOC](letcode 分类练习 226.翻转二叉树 101. 对称二叉树 104.二叉树的最大深度 111.二叉树的最小深度)

letcode 分类练习 226.翻转二叉树 101. 对称二叉树 104.二叉树的最大深度 111.二叉树的最小深度 226.翻转二叉树101. 对称二叉树104.二叉树的最大深度111.二叉树的最小深度 226.翻转二叉树 利用自底向上的遍历交换左子树和右子树 class Solution { public:TreeNode* invertTr…

后端Web之数据库(以MySQL为例)

目录 1.概述 2.MySQL 3.DDL 4.DML 5.DQL 1.概述 对于我们自己写的一些小功能&#xff0c;数据一般存储在文件中&#xff0c;比如XML文件。而在实际项目中&#xff0c;数据都是存放在数据库中的。数据库&#xff08;DataBase &#xff09;是一个存储数据的集合&#xff0c…

双剑合璧,网络无敌!Windows Server 2012 R2双网卡绑定实战教程

文章目录 双剑合璧&#xff0c;网络无敌&#xff01;Windows Server 2012 R2双网卡绑定实战教程1 背景信息2 配置步骤2.1 登录服务器2.2 分别清除两块网卡的配置2.3 进入“本地服务器”界面2.4 进入“NIC组合”界面2.5 创建网卡绑定组2.6 设置新建组参数2.7 查看已创建的网卡组…

【计算机硬件蓝光光驱】

蓝光光驱&#xff08;Blu-ray Disc Drive&#xff09;是一种光盘驱动器&#xff0c;用于读取和写入蓝光光盘。蓝光光盘是一种高容量、高清晰度的光存储介质&#xff0c;用于存储视频、音频、数据等多种媒体内容。蓝光光驱的名称“蓝光”来源于其使用的蓝色激光光束&#xff0c;…

Windows 安装 及解决 tvm 无法打开 源 文件 “dmlc/logging.h“

如果你在编译 TVM 时遇到 dmlc/logging.h 文件缺失的问题&#xff0c;很可能是因为在克隆 TVM 仓库时没有包含其子模块&#xff0c;而这些子模块&#xff08;如 dmlc-core&#xff09;是通过 Git 管理的。解决步骤 安装 Git&#xff1a; 如果你还没有安装 Git&#xff0c;需要先…

ES6学习笔记(九)——class(类)

1. 封装 传统面向对象的编程序语言都是【类】的概念&#xff0c;对象都是由类创建出来&#xff0c;然而早期 JavaScript 中是没有类的&#xff0c;面向对象大多都是基于构造函数和原型实现的&#xff0c;但是 ECMAScript 6 规范开始增加了【类】相关的语法&#xff0c;使得 Ja…

虚幻5|AI视力系统,听力系统,预测系统(1)视力系统

继宠物伴随系统初步篇后续 虚幻5|AI巡逻宠物伴随及定点巡逻—初步篇-CSDN博客 一&#xff0c;听力系统 1.打开宠物ai的角色蓝图 2.选中ai感知组件 右侧细节&#xff0c;找到ai感知&#xff0c;添加感知配置&#xff0c;我们需要的是ai视力配置 3.选中左侧创建的ai感知组件&…

CLRerNet推理详解及部署实现(上)

目录 前言1. 概述2. 环境配置3. Demo测试4. ONNX导出初探5. ONNX导出优化6. ONNX导出总结结语下载链接参考 前言 继续我们的车道线检测任务&#xff0c;之前我们分享了基于 anchor 的 LaneATT 模型以及 CVPR2022 的 SOTA 方案 CLRNet&#xff0c;这里我们分享 WACV2024 中的一个…

如何在Linux系统上使用ONLYOFFICE文档编辑PDF文件

​对Linux用户来说&#xff0c;得益于各类免费PDF编辑器&#xff0c;编辑PDF文件从来都不是无解难题。 如果您需要为PDF文件添加注释、留下批注、编辑已有文本或添加新文本框、插入图片或形状、删除某些页面或永久删除页面&#xff0c;您始终可以找到合适的应用&#xff0c;轻…

有关JavaScript的函数定义和函数的两种声明方式

1.函数 函数是一段可重复执行的代码块&#xff0c;它可以接收参数&#xff0c;并返回结果。在JavaScript中&#xff0c;函数用于封装可重用的代码&#xff0c;提高代码的可读性和可维护性。 1.1 函数的定义 函数的定义包括以下几个部分&#xff1a; 函数名称&#xff1a;用…

Hive3:表性能优化-分区与分桶

一、分区 1、概念 我们知道&#xff0c;一个Hive表&#xff0c;对应的HDFS是一个文件夹。 那么&#xff0c;当数据非常多的时候&#xff0c;存放在一个文件夹中&#xff0c;后期进行查询操作会影响性能。 所以&#xff0c;Hive引入了分区管理的方式。 本质就是&#xff0c;在…

Datawhale X 魔搭 AI夏令营-AIGC方向-LoRA学习笔记

LoRA&#xff08;Low-Rank Adaptation&#xff09;是一种用于优化大规模预训练模型的微调技术&#xff0c;特别适用于在资源有限的情况下&#xff0c;对模型进行高效且低成本的微调。LoRA的核心思想是通过低秩分解方法&#xff0c;仅微调模型的少数参数&#xff0c;从而显著减少…

关于图像亮度相关的调试总结

1、问题背景 关于图像亮度的调试&#xff0c;是整个ISP中非常重要的一块&#xff0c;它决定了图像整体的亮度、对比度、细节、以及噪声&#xff0c;对人眼有非常直观的感受&#xff0c; 之前也就具体问题&#xff0c;整理过几篇图像亮度模块相关的调试总结&#xff1a; 关于图…

标题中有多少个字符(c语言)

1.//描述 //凯刚写了一篇美妙的作文&#xff0c;请问这篇作文的标题中有多少个字符&#xff1f; //注意&#xff1a;标题中可能包含大、小写英文字母、数字字符、空格和换行符。统计标题字 符数时&#xff0c;空格和换行符不计算在内。 //输入描述&#xff1a; //输入文件只有一…

【12】KMP和Manacher算法

目录 一.KMP算法解决的问题 二.Manacher算法解决的问题 基本概念 优化 一.KMP算法解决的问题 暴力求解复杂度O(N*M) next数组&#xff1a;next[i]表示arr[0...i-1]的前缀和后缀的最长公共长度。 Y位置失败&#xff0c;将前缀和后缀完全匹配&#xff0c;将前缀的部分和后缀对…

软件测试---接口自动化

一、pythonrequests模块 &#xff08;1&#xff09;requests全局观 安装&#xff1a;pip install requests 1.发送请求 ①requests.get() 发送get请求 ②requests.post() 发送post请求 data和json的区别&#xff1a;取绝于你需要传递的参数的类型。 files&#xff1a;文件上…

大学成长之路:如何从烧锅炉的逆袭成为FPGA大厂高管

如何从烧锅炉的逆袭成为FPGA大厂Sales Director 在即将到来的开学季&#xff0c;很多学子从高中生成为一个大学生&#xff0c;走入新的征程。大学生涯是人生的一个非常重要的阶段&#xff0c;如何度过大学4年的时光&#xff0c;并学有所成&#xff0c;是很多大学新生和家长思考…

Spring IoCDI(下)—DI的尾声

我们之前学习了控制反转IoC&#xff0c;接下来就开始学习依赖注入DI的细节。 依赖注入是一个过程&#xff0c;是指IoC容器在创建Bean时&#xff0c;去提供运行时所依赖的资源&#xff0c;而资源指的就是对象。我们使用 Autowired 注解&#xff0c;完成依赖注入的操作。简单来说…

AMBA-CHI协议详解(六)

AMBA-CHI协议详解&#xff08;一&#xff09; AMBA-CHI协议详解&#xff08;二&#xff09; AMBA-CHI协议详解&#xff08;三&#xff09; AMBA-CHI协议详解&#xff08;四&#xff09; AMBA-CHI协议详解&#xff08;五&#xff09; AMBA-CHI协议详解&#xff08;六&#xff09…

JavaSocket编程+JDBC实战技术

一、JavaSocket编程 1.1HTTP协议 后端原理 2. 特点 同步&#xff1a;就是两个任务执行的过程中&#xff0c;其中一个任务要等另一个任务完成某各阶段性工作才能继续执行&#xff0c;如厨师A炒番茄&#xff0c;将葱花放入锅中&#xff0c;然后需要放入番茄&#xff0c;但是厨…