剑指 Offer 12. 矩阵中的路径
摘要
剑指 Offer 12. 矩阵中的路径
一、回溯算法解析
本问题是典型的矩阵搜索问题,可使用 深度优先搜索(DFS)+ 剪枝解决。
- 深度优先搜索: 可以理解为暴力法遍历矩阵中所有字符串可能性。DFS 通过递归,先朝一个方向搜到底,再回溯至上个节点,沿另一个方向搜索,以此类推。
- 剪枝: 在搜索中,遇到 这条路不可能和目标字符串匹配成功 的情况(例如:此矩阵元素和目标字符不同、此元素已被访问),则应立即返回,称之为 可行性剪枝 。
DFS 解析:
递归参数:当前元素在矩阵 board 中的行列索引i和j ,当前目标字符在word中的索引k。
终止条件:
- 返回false :(1) 行或列索引越界或(2) 当前矩阵元素与目标字符不同或(3) 当前矩阵元素已访问过 ((3) 可合并至 (2) ) 。
- 返回 true:k = len(word) - 1 ,即字符串 word 已全部匹配。
递推工作:
- 标记当前矩阵元素: 将 board[i][j] 修改为 空字符 '' ,代表此元素已访问过,防止之后搜索时重复访问。
- 搜索下一单元格: 朝当前元素的 上、下、左、右 四个方向开启下层递归,使用 或 连接 (代表只需找到一条可行路径就直接返回,不再做后续 DFS ),并记录结果至 res 。
- 还原当前矩阵元素: 将 board[i][j] 元素还原至初始值,即 word[k] 。
返回值: 返回布尔量 res ,代表是否搜索到目标字符串。
package matrix;/*** @Classname JZ12矩阵中的路径* @Description* 设函数 check(i,j,k) 表示判断以网格的 (i,j) 位置出发,能否搜索到单词 word[k..],其中 word[k..]* 表示字符串 word从第 k 个字符开始的后缀子串。如果能搜索到,则返回 true,反之返回 false。** 函数 check(i,j,k) 的执行步骤如下:* 如果 board[i][j]≠s[k],当前字符不匹配,直接返回 false。* 如果当前已经访问到字符串的末尾,且对应字符依然匹配,此时直接返回 true。* 否则,遍历当前位置的所有相邻位置。如果从某个相邻位置出发,能够搜索到子串 word[k+1..],则返回 true,否则返回 false* 这样,我们对每一个位置 (i,j)都调用函数 check(i,j,0) 进行检查:只要有一处返回 true,就说明网格中能够找到相应的单词,否则说明不能找到。* @Date 2022/12/6 9:54* @Created by xjl*/
public class JZ12矩阵中的路径 {int[][] dict=new int[][]{{0, 1}, {0, -1}, {1, 0}, {-1, 0}};/*** @description 使用回溯算法来实现* @param: board* @param: word* @date: 2022/12/6 10:12* @return: boolean* @author: xjl*/public boolean exist(char[][] board, String word) {int h = board.length, w = board[0].length;// 判断时候访问的标志boolean[][] visited = new boolean[h][w];// 逐个遍历来实现for (int i = 0; i < h; i++) {for (int j = 0; j < w; j++) {// 数组传递 访问标志位 当前的i j的位置 目标word 当前的匹配的字符数boolean flag = check(board, visited, i, j, word, 0);if (flag) {return true;}}}return false;}/*** @description* @param: board 查找的数组* @param: visited 是否已经访问了的数据* @param: i 当前的位置坐标* @param: j 当前的位置坐标* @param: word 目标单词* @param: k 当前匹配的字符数* @date: 2022/12/6 10:15* @return: boolean* @author: xjl*/private boolean check(char[][] board, boolean[][] visited, int i, int j, String word, int k) {// 如果 board[i][j]≠s[k],当前字符不匹配,直接返回 false。if (board[i][j] != word.charAt(k)) {return false;} else if (k == word.length() - 1) {// 表示匹配完成了 就返回truereturn true;}// 访问当前元素visited[i][j] = true;// 设置当前访问的结果 通过判断下一次的结果来 判断是否全部匹配成功了。boolean result = false;for (int[] dir : dict) {int newi = i + dir[0],newj = j + dir[1];// 保证需要在矩阵的内部if (newi >= 0 && newi < board.length && newj >= 0 && newj < board[0].length) {// 表示没有访问过if (!visited[newi][newj]){boolean flag=check(board,visited,newi,newj,word,k+1);if (flag){result=true;break;}}}}// 设置回来,表示的没有访问过。visited[i][j]=false;return result;}public boolean exist2(char[][] board, String word) {//对应的字符创数组char[] words = word.toCharArray();//开始重第一个开始遍历for(int i = 0; i < board.length; i++) {for(int j = 0; j < board[0].length; j++) {if(dfs(board, words, i, j, 0)) {return true;}}}return false;}//k 表示的是字符数组的下标的位置boolean dfs(char[][] board, char[] word, int i, int j, int k) {//i越界 j越界 字符串不等于数组的这个元素if(i >= board.length || i < 0 || j >= board[0].length || j < 0 || board[i][j] != word[k]) {return false;}//当遍历完成了这返回trueif(k == word.length - 1) {return true;}// 当前字符串char tmp = board[i][j];board[i][j] = '/';//表示是矩阵中的下上右左的是否为下一个boolean res = dfs(board, word, i + 1, j, k + 1) || dfs(board, word, i - 1, j, k + 1) || dfs(board, word, i, j + 1, k + 1) || dfs(board, word, i , j - 1, k + 1);// 回溯board[i][j] = tmp;//返回这个数据return res;}int[][] dirct=new int[][]{{1,0},{-1,0},{0,1},{0,-1}};public boolean exist3(char[][] board, String word) {int h=board.length;int w=board[0].length;boolean[][] visit=new boolean[h][w];for (int i=0;i<h;i++){for (int j=0;j<w;j++){boolean result=check3(board,visit,i,j,word,0);if (result){return true;}}}return false;}private boolean check3(char[][] board, boolean[][] visit, int i, int j, String word, int k) {if (board[i][j]!=word.charAt(k)){return false;}if (k==word.length()-1){return true;}visit[i][j]=true;boolean result=false;for (int[] dir:dirct){int newi=i+dir[0];int newj=j+dir[1];if (newi>=0&&newi<board.length&&newj>=0&&newj<board[0].length){if (!visit[newi][newj]){boolean res=check(board,visit,newi,newj,word,k+1);if (res){result=true;break;}}}}visit[i][j]=false;return result;}}
复杂度分析:
M,N 分别为矩阵行列大小, K为字符串word长度。
- 时间复杂度 O((3^K)MN) : 最差情况下,需要遍历矩阵中长度为K字符串的所有方案,时间复杂度为 O(3K);矩阵中共有MN个起点,时间复杂度为O(MN) 。
- 空间复杂度 O(K): 搜索过程中的递归深度不超过K ,因此系统因函数调用累计使用的栈空间占用 O(K)(因为函数返回后,系统调用的栈空间会释放)。最坏情况下 K=MN,递归深度为MN ,此时系统栈使用 O(MN)的额外空间。
博文参考
《leetcode》
相关文章:

剑指 Offer 12. 矩阵中的路径
摘要 剑指 Offer 12. 矩阵中的路径 一、回溯算法解析 本问题是典型的矩阵搜索问题,可使用 深度优先搜索(DFS) 剪枝解决。 深度优先搜索: 可以理解为暴力法遍历矩阵中所有字符串可能性。DFS 通过递归,先朝一个方向搜…...

springboot+jersey+tomcat实现跨域方式上传文件到服务器
前言 在服务器上,当我们启动了tomcat,就可以以 http://ip地址:8080/文件路径/文件名 的方式,进行访问到我们服务器上处于tomcat的webapps文件夹下的文件 于是为了可以往上面加文件,我们有两种方式,一种就是直接复制文…...

【微信小程序】-- 常用视图容器类组件介绍 -- view、scroll-view和swiper(六)
💌 所属专栏:【微信小程序开发教程】 😀 作 者:我是夜阑的狗🐶 🚀 个人简介:一个正在努力学技术的CV工程师,专注基础和实战分享 ,欢迎咨询! &#…...

猜数字游戏——C++
我们在有了一定的C基础了以后,简单的实现一个案例(其实只要会while循环结构就行了),我们本章内容会实现猜数字游戏,大家有什么语法疑问可以看看我写的:C快速入门_染柒_GRQ的博客-CSDN博客,该博客…...
整数对最小和
题目描述 给定两个整数数组 array1 array2。数组元素按升序排列,假设从array1 、array2中分别取出一个元素可构成一对元素,现在需要取出K个元素并对取出的所有元素求和,计算和的最小值 注意事项 两对元素如果对应于array1 array2中的两个下…...
2023-2-22 -javaagent
周三,天气晴,7度 Java Agent Java Agent也叫作java探针,可以实现动态修改java字节码,完成额外的功能。在java类编译成字节码,在jvm执行之前,它可以读取修改字节码,以来完成额外的功能。 使用…...

JavaScript BOM操作
目录 前言 window 对象 location 对象 navigator 对象 screen 对象 history 对象 前言 BOM(Browser Object Model)指的是浏览器对象模型,它是 JavaScript 和浏览器之间的接口。通过 BOM,JavaScript 可以与浏览器窗口交互&…...

【机器学习 | 强基计划】开山篇 | 机器学习介绍及其类别和概念阐述
🤵♂️ 个人主页: @计算机魔术师 👨💻 作者简介:CSDN内容合伙人,全栈领域优质创作者。 机器学习 | 强基计划系列 (一) 作者: 计算机魔术师 版本: 1.0 ( 2022.2.25) 注释:文章会不定时更新补充 文章目录 前言一、机器学习概览1.1 有监督学习和无监督学习1.1.…...
华为OD机试真题Java实现【合规数组】真题+解题思路+代码(20222023)
合规数组 题目 给定一个正整数数组 检查数组中是否存在满足规则的数组组合 规则: A = B + 2C 🔥🔥🔥🔥🔥👉👉👉👉👉👉 华为OD机试(Java)真题目录汇总 ## 输入 第一行输出数组的元素个数 接下来一行输出所有数组元素,用空格隔开 输出 如果存在满…...

BoostSearcher搜索引擎项目
BoostSearcher搜索引擎项目 1.BoostSearcher这个项目是什么? 答:一个为Boost文档建立索引的站内搜索引擎,简单的说就是一个类似于csdn站内文档搜索框。 项目展示: gitee:https://gitee.com/zxlfx/boost-search-engine-project …...

【模拟集成电路】频率综合器(Frequency Synthesizer,FS)设计
应用于无线局域网的频率综合器设计前言频率综合器简介各部分链接链接:前言 本文主要内容是对频率综合器或称为PLL 做出简单介绍,为课程设计部分章节内容,后需给出各部分的设计方案,以及测试结果。 频率综合器简介 无线收发系统中…...

实例8:机器人的空间描述和变换仿真
实例8:机器人的空间描述和变换仿真 实验目的 通过刚体与刚体的平动、转动基础知识的学习,熟悉位姿的描述通过Python编程实践,可视化学习坐标系的变换,熟悉空间变换 实验要求 通过python编程,输入一指定向量和对应的…...
网络 导航
目录内容链接网络网络参考文章:【网络】http请求 调试网络问题解决参考文章:【问题解决】网络 IP DNS解析网络问题解决参考文章:【问题解决】网络 TCP 规则 抓包网络问题解决参考文章:【问题解决】网络 Http请求 调试网络问题解决…...

Web Spider Ast-Hook 浏览器内存漫游-数据检索
文章目录一、资源下载二、通过npm安装anyproxy模块三、anyproxy的介绍以及基本使用1. anyproxy的功能介绍2. anyproxy的基本使用四、给浏览器挂代理五、实操极验demo案例总结提示:以下是本篇文章正文内容,下面案例可供参考 一、资源下载 Github&#x…...

计算机网络笔记、面试八股(二)——HTTP协议
本章目录2. HTTP协议2.1 HTTP协议简介2.2 HTTP协议的优点2.3 HTTP协议的缺点2.4 HTTP协议属于哪一层2.5 HTTP通信过程2.6 常见请求方法2.7 GET和POST的区别2.8 请求报文与响应报文2.8.1 HTTP请求报文2.8.2 HTTP响应报文2.9 响应状态码2.10 HTTP 1.0和1.1的区别2.10.1 长连接2.1…...

docker快速上手使用
文章目录一、docker概述1. 为什么需要docker2. 什么是docker3. docker和虚拟机的区别4. docker三要素二、docker安装1. 添加app源2. 安装docker社区版3. 更换国内docker镜像源三、docker基本使用方法1. 获取镜像2. 查看当前系统中的docker镜像3. 运行docker容器4. 查看当前存在…...

<c++> 类的构造函数与类的析构函数
文章目录类的构造函数什么是构造函数声明和定义构造函数如何使用构造函数默认构造函数类的析构函数什么是析构函数声明和定义析构函数小练习银行账户执行效果类的构造函数 什么是构造函数 Q:什么是类的构造函数 A:构造函数是类的一种特殊成员函数,不需…...
华为OD机试真题Java实现【玩牌高手】真题+解题思路+代码(20222023)
玩牌高手 给定一个长度为n的整型数组,表示一个选手在n轮内可选择的牌面分数。选手基于规则选牌, 请计算所有轮结束后其可以获得的最高总分数。 选择规则如下: 1、在每轮里选手可以选择获取该轮牌面,则其总分数加上该轮牌面分数,为其新的总分数。 2、选手也可不选择本轮…...
Hive Sql整体优化思路
如果遇到sql性能问题,可以先查看4040页面的sql执行信息。一个sql解析为多个stage,一个stage分为多个task。对问题Sql的某一个stage,基本的分析思路如下:所有的task都慢,检查下是否有笛卡尔积(关联字段重复值、关联字段…...

【华为OD机试模拟题】用 C++ 实现 - 数组的中心位置(2023.Q1)
最近更新的博客 华为OD机试 - 入栈出栈(C++) | 附带编码思路 【2023】 华为OD机试 - 箱子之形摆放(C++) | 附带编码思路 【2023】 华为OD机试 - 简易内存池 2(C++) | 附带编码思路 【2023】 华为OD机试 - 第 N 个排列(C++) | 附带编码思路 【2023】 华为OD机试 - 考古…...
Python爬虫实战:研究feedparser库相关技术
1. 引言 1.1 研究背景与意义 在当今信息爆炸的时代,互联网上存在着海量的信息资源。RSS(Really Simple Syndication)作为一种标准化的信息聚合技术,被广泛用于网站内容的发布和订阅。通过 RSS,用户可以方便地获取网站更新的内容,而无需频繁访问各个网站。 然而,互联网…...
五年级数学知识边界总结思考-下册
目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解:由来、作用与意义**一、知识点核心内容****二、知识点的由来:从生活实践到数学抽象****三、知识的作用:解决实际问题的工具****四、学习的意义:培养核心素养…...

MODBUS TCP转CANopen 技术赋能高效协同作业
在现代工业自动化领域,MODBUS TCP和CANopen两种通讯协议因其稳定性和高效性被广泛应用于各种设备和系统中。而随着科技的不断进步,这两种通讯协议也正在被逐步融合,形成了一种新型的通讯方式——开疆智能MODBUS TCP转CANopen网关KJ-TCPC-CANP…...
[Java恶补day16] 238.除自身以外数组的乘积
给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法,且在 O(n) 时间复杂度…...
蓝桥杯 冶炼金属
原题目链接 🔧 冶炼金属转换率推测题解 📜 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V,是一个正整数,表示每 V V V 个普通金属 O O O 可以冶炼出 …...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
Leetcode33( 搜索旋转排序数组)
题目表述 整数数组 nums 按升序排列,数组中的值 互不相同 。 在传递给函数之前,nums 在预先未知的某个下标 k(0 < k < nums.length)上进行了 旋转,使数组变为 [nums[k], nums[k1], …, nums[n-1], nums[0], nu…...

ubuntu系统文件误删(/lib/x86_64-linux-gnu/libc.so.6)修复方案 [成功解决]
报错信息:libc.so.6: cannot open shared object file: No such file or directory: #ls, ln, sudo...命令都不能用 error while loading shared libraries: libc.so.6: cannot open shared object file: No such file or directory重启后报错信息&…...
绕过 Xcode?使用 Appuploader和主流工具实现 iOS 上架自动化
iOS 应用的发布流程一直是开发链路中最“苹果味”的环节:强依赖 Xcode、必须使用 macOS、各种证书和描述文件配置……对很多跨平台开发者来说,这一套流程并不友好。 特别是当你的项目主要在 Windows 或 Linux 下开发(例如 Flutter、React Na…...
6️⃣Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙
Go 语言中的哈希、加密与序列化:通往区块链世界的钥匙 一、前言:离区块链还有多远? 区块链听起来可能遥不可及,似乎是只有密码学专家和资深工程师才能涉足的领域。但事实上,构建一个区块链的核心并不复杂,尤其当你已经掌握了一门系统编程语言,比如 Go。 要真正理解区…...