穷举深搜暴搜回溯剪枝(4)

一)单词搜索:

直接在矩阵中依次找到特定字符串

79. 单词搜索 - 力扣(LeetCode)

画出决策树,只需要做一个深度优先遍历:

1)设计dfs函数:只需要关心每一层在做什么即可,从这个节点开始,开始去尝试匹配字符串的下一个字符,就是从某一个位置的字符开始,上下左右下标看看能不能匹配下一个字符给定一个节点的位置,上下左右去匹配一个结点的位置,dfs(char[][] board,i,j,s,pos),把原始的矩阵给定,把这个字符的位置,把要匹配字符串,字符串匹配到哪一个位置

2)从i,j位置开始上下左右去搜索word的哪一个字符就可以了

3)boolean返回值代表此次路径的选择是成功还是失败

2)二维矩阵中要注意的细节问题:

在二维矩阵搜索的过程中不能走重复的路,要想解决这个问题,可以有两种方法:

2.1)使用一个和原始矩阵相同规模大小的布尔数组,如果这个字符已经被路径走过了,那么直接修改成true

2.2)直接修改原始矩阵的值,如果某一个字符被走过了,那么直接修改字符为.或者其他标记字符

假设在下面的这个例子中给定我们一个矩阵,给定一个字符串A="AAAA"判断是否可以匹配成功

2.3)当我们第一次成功的匹配到了A字符的时候,将这个A字符标记成true,表示这个字符已经被使用过了,此时想左匹配第二个A字符,当尝试在第二个A字符中匹配第三个A字符的时候,此时是不能再继续想左找第一个A字符了,此时因为第一个A字符已经被使用过了

class Solution {public boolean[][] check;int row;int col;
//利用向量数组一个for循环搞定上下左右四个方向int[] dx={0,0,1,-1};int[] dy={1,-1,0,0};public boolean dfs(char[][] board,String word,int i,int j,int pos){if(pos==word.length()) return true;//当匹配到最后一个字符之后直接返回//接下来向上下走有去匹配word[pos];for(int k=0;k<4;k++){
//从这里面开始左每一层所做的事情,从(i,j)下标开始上下左右去匹配pos位置的字符int x=i+dx[k];int y=j+dy[k];
if(x>=0&&x<row&&y>=0&&y<col&&check[x][y]==false&&board[x][y]==word.charAt(pos))
{check[x][y]=true;if(dfs(board,word,x,y,pos+1)) return true;check[x][y]=false;
}}return false;//匹配失败在这里面返回说明上下左右都匹配不到想要的字符}
//此时如果不加上返回值的话,那么匹配成功也是返回return;
//此时匹配失败也就是说上下左右找不到特定字符也是返回return;此时主函数就不知道最终是返回true还是false的public boolean exist(char[][] board, String word) {
//1.先进行计算二维数组的行和列,初始化布尔数组this.row=board.length;this.col=board[0].length;this.check=new boolean[row][col];
//2.现在整个数组中找到字符串中第一个字符出现的位置,然后去尝试匹配下一个字符for(int i=0;i<row;i++){for(int j=0;j<col;j++){if(board[i][j]==word.charAt(0)){
//先进行遍历整个矩阵直到我们找到第一个位置的时候才会向下进行搜索check[i][j]=true;if(dfs(board,word,i,j,1)==true) return true;
//判断从这个位置开始尝试是否正确check[i][j]=false;}}}
//3.代码走到这里说明所有枚举的第一个位置都无法匹配s这个字符串,所以直接返回falsereturn false;}
}

二)黄金矿工:

算法原理:

1)这个题和上一个题的起始dfs位置是存在着差别的,上一道题必须是从字符串的第一个位置开始才可以进行向下dfs,而这个题从上下左右边界任意位置开始进行dfs都可以

2)开采过的位置不能再挖,0号位置不能再挖

3)枚举所有位置为起点,进行爆搜

1219. 黄金矿工 - 力扣(LeetCode)

class Solution {int ret=0;int row=0;int col=0;public boolean[][] check;int[] dx={0,0,1,-1};int[] dy={1,-1,0,0};public void dfs(int[][] array,int i,int j,int glod){glod+=array[i][j];ret=Math.max(glod,ret);for(int k=0;k<4;k++){int x=i+dx[k];int y=j+dy[k];
if(x>=0&&x<row&&y>=0&&y<col&&!check[x][y]&&array[x][y]!=0){check[x][y]=true;dfs(array,x,y,glod);check[x][y]=false;
}}}public int getMaximumGold(int[][] array) {this.row=array.length;this.col=array[0].length;this.check=new boolean[row][col];for(int i=0;i<array.length;i++){for(int j=0;j<array[0].length;j++){if(array[i][j]==0) continue;else{check[i][j]=true;dfs(array,i,j,0);//这个二层循环的目的就是从每一个位置开始开始挖此时能获取到的最大黄金数check[i][j]=false;}}}return ret;}
}

三)不同路径

算法原理:在矩阵中进行搜索,先找到1的位置,从这个起始位置开始进行深度优先遍历,然后进行判断这条路径是否合法即可,解决方法就是在进行向下递归的过程中使用count变量来记录一下,从起始位置开始记录一下行走步数,到达最终结果之后,再进行对比和实际要走的步数是否相同(整个数组0的个数)

980. 不同路径 III - 力扣(LeetCode)

class Solution {//这样处理的目的就是我所走的所有路径的格子数等于总的格子数public int step=2;//表示处理第一个数和最后一个数public boolean[][] check;public int row=0;public int col=0;public int count=1;//表示处理第一个数public int ret=0;int[] dx={0,0,1,-1};int[] dy={1,-1,0,0};public void dfs(int[][] array,int i,int j){if(array[i][j]==2){if(step==count){System.out.println(ret);ret++;}return;}for(int k=0;k<4;k++){int x=i+dx[k];int y=j+dy[k];
if(x>=0&&x<row&&y>=0&&y<col&&!check[x][y]&&array[x][y]!=-1){check[x][y]=true;count++;dfs(array,x,y);count--;check[x][y]=false;
}}}public int uniquePathsIII(int[][] array) {this.row=array.length;this.col=array[0].length;this.check=new boolean[row][col];
//1.先进行处理整个方形格子中的0的个数int dx=0;int dy=0;for(int i=0;i<row;i++){for(int j=0;j<col;j++){if(array[i][j]==0) step++;else if(array[i][j]==1){dx=i;dy=j;}}}
//2.先找到1的位置check[dx][dy]=true;dfs(array,dx,dy);return ret;}
}

四)递增子序列

算法原理:

1)这个题的剪枝策略一共有两步:

1.2)在同一层内,相同的元素重复出现的要剪掉

1.3)在每一层内进行枚举,从pos+1的位置开始进行枚举,防止使用到上一层已经使用过的元素

1.3)在本层进行枚举元素的时候,一定要比上一层的最后一个元素要大,但是如果path中没有任何元素,那么就可以放心地向里面添加元素

491. 递增子序列 - 力扣(LeetCode)

class Solution {List<List<Integer>> ret=new ArrayList<>();List<Integer> path=new ArrayList<>();public void dfs(int[] nums,int pos){if(path.size()>=2){ret.add(new ArrayList<>(path));}
HashSet<Integer> set=new HashSet<>();
//将本层的所有元素保存起来,防止重复for(int i=pos;i<nums.length;i++){
if((path.size()==0||path.get(path.size()-1)<=nums[i])&&!set.contains(nums[i])){path.add(nums[i]);set.add(nums[i]);dfs(nums,i+1);path.remove(path.size()-1);
}}}public List<List<Integer>> findSubsequences(int[] nums) {dfs(nums,0);return ret;}
}

五)分割回文串

131. 分割回文串 - 力扣(LeetCode)

1)什么是切割线?startIndex后面应该被切割的字符串的第一个位置,第一个分割线就是在startIndex第一个字符后面的

2)如何表示切割的子串的范围?[startIndex,i],i一开始等于startIndex,此时切割线在i所指向的字符的后面

class Solution {List<List<String>> ret=new ArrayList<>();boolean[][] dp=null;List<String> path=new ArrayList<>();public void dfs(String s,int startIndex){if(startIndex==s.length()){ret.add(new ArrayList<>(path));return;}
//注意单层递归的逻辑for(int i=startIndex;i<s.length();i++){if(dp[startIndex][i]==true){
//判断当前选择切割的这一段部分是否是回文串,如果不是回文串,那么当前位置作废,直接进行剪枝操作path.add(s.substring(startIndex,i+1));
//此时这个分割线在i+1这个字符的后面dfs(s,i+1);path.remove(path.size()-1);}else{continue;}}}public List<List<String>> partition(String s) {
//1.首先创建一个dp表,dp[i][j]表示以i位置元素为起点,j位置字符为终点,是否这个子串是一个回文串
this.dp=new boolean[s.length()][s.length()];//从下到上,从走向右进行填表for(int i=s.length()-1;i>=0;i--){for(int j=i;j<s.length();j++){if(s.charAt(i)==s.charAt(j)){if(i==j) dp[i][j]=true;else if(i+1==j) dp[i][j]=true;else{dp[i][j]=dp[i+1][j-1];}}else{dp[i][j]=false;}}}//2.然后进行回溯操作dfs(s,0);return ret;}
}

六)复原IP地址

93. 复原 IP 地址 - 力扣(LeetCode)

一)题目解析:

1)什么是有效的IP地址呢?

1.1)首先这个IP地址的经过逗号分割的单独一个部分可以包含一个0,但是一个数字前面不能出现前导0,就比如说0.011.122.32

1.2)还有经过逗号分割的每一个部分的值都是小于255的,例如192.168.1.455

1.3)如果给定的字符串中出现了非正整数字符的话,那么它本身也是一个非法的IP地址

所以本题我们不光要对字符串进行切割处理,还需要针对切割出来的每一个字符串要做一个合法性的判断

二)算法原理:
dfs参数的设计:

1)在我们的dfs函数的参数里面有一个变量叫做startIndex,主要作用就是从本层开始当进入到下一层递归的时候要从剩下的字符串的哪一个位置开始进行切割

2)传入应该被切割的字符串

3)要加入的IP地址的点的数量,其实这个IP地址的点的数量就决定了这颗决策树的深度,决策树的高度其实就是三就可以了,也没有必要向下进行切割了,如果你继续向下切割,那么只能会多增加逗点,此时这个IP地址固定不是一个合法的IP地址了

返回值:

还有当进入到递归出口的时候,要对最后一个字符串做合法性的判断,如果这个最后一个字符串也合法,最后才可以加入到最终的结果集里面,这个判断函数,数字前面不能有0,区间长度不能超过255,不能出现除了数字外的字符

dfs函数有就是每一层要做的事:

1)枚举每一个切割线的位置进行切割,如果发现切割线切除的字符串不是一个合法的字符串,就没有必要继续向下进行深度优先遍历了,直接向上返回就可以了

2)如果发现被这个切割线的子串是一个合法的字符串(s.substring(startIndex,i+1),那么就将这个字符串加入到path里面,同时开始进行枚举下一层最后回到本层的时候别忘了恢复现场

3)注意本体有一道坑,这个num这个数应该写在for循环的里面,因为num所传递的数可能已经超过了整数可以表示的最大范围;

class Solution {List<String> ret=new ArrayList<>();StringBuilder path=new StringBuilder();public int pointNum=0;//判断字符串s在左闭右闭区间[start,end]区间内是否合法public boolean isValid(String s,int start,int end){if(s.equals("")) return false;if(start>end) return false;//以0为开始的字符不合法if(s.charAt(start)=='0'&&start!=end) return false;int num=0;for(int i=start;i<=end;i++){if(s.charAt(i)>'9'||s.charAt(i)<'0') return false;num=num*10+(s.charAt(i)-'0');}if(num>255) return false;return true;}public void dfs(String s,int startIndex){
//1.处理递归出口if(pointNum==3){
//说明此时逗号数量是3,分割结束,此时判断第四段字符串是否合法,如果合法就加入到result中
if(isValid(s,startIndex,s.length()-1)){
//将最后一个字符串加入到path中path.append(s.substring(startIndex,s.length()));ret.add(path.toString());
//恢复现场,注意这里面不是s.length()-1path.delete(startIndex+2,path.length()-1);}return; }
//2.处理每一层所干的事for(int i=startIndex;i<s.length();i++){if(isValid(s,startIndex,i)){path.append(s.substring(startIndex,i+1));pointNum++;path.append(".");dfs(s,i+1);pointNum--;path.delete(startIndex+pointNum,i+pointNum+2);}}}public List<String> restoreIpAddresses(String s) {// if(s.length()>12) return ret;dfs(s,0);return ret;}
}

七)不同的二叉搜索树

95. 不同的二叉搜索树 II - 力扣(LeetCode)

算法原理:

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Xshell远程访问工具连接到Linux

首先需要查看Linux地址&#xff0c;在Linux主界面中右键选择“Open in Terminal” 输入“ifconfig”指令查看IP地址 打开Xshell&#xff0c;输入相关信息&#xff0c;建立连接 点击连接&#xff0c;按照提示输入用户名 root和你自己安装centos7时设置的密码&#xff0c;用…

OpenCV_CUDA_VS编译安装

一、OpenCV 我这里是下载的OpenCV4.5.4&#xff0c;但是不知道到在vs里面build时一直报错&#xff0c;后面换了4.7.0的版本测试&#xff0c;安装成功。 Release OpenCV 4.5.4 opencv/opencv GitHub 这个里面有官方预编译好的OpenCV库&#xff0c;可以直接食用。 扩展包&am…

React 展开运算符

0x00 前言 CTF 加解密合集CTF Web合集网络安全知识库溯源相关 文中工具皆可关注 皓月当空w 公众号 发送关键字 工具 获取 0x01 展开运算符 1. 展开数组 <script type"text/javascript">let arr1 [1,3,5,7,9]let arr2 [2,4,6,8,10]console.log(...arr1)&l…

TCP IP网络编程(四) 基于TCP的服务器端、客户端

文章目录 理解TCP、UDPTCP/IP协议栈链路层IP层TCP/UDP层应用层 实现基于TCP的服务器端、客户端TCP服务器端的默认函数调用顺序进入等待连接请求状态受理客户端连接请求TCP客户端的默认函数调用顺序基于TCP的服务器端、客户端函数调用关系 实现迭代服务器端、客户端实现迭代服务…

RK3399平台开发系列讲解(内核调试篇)spidev_test工具使用

🚀返回专栏总目录 文章目录 一、环境二、执行测试三、回环测试四、字节发送测试五、32位数据发送测试沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 在 Linux 系统上,“spidev_test” 是一个用于测试和配置 SPI(Serial Peripheral Interface)设备的命令行工具。…

Java拓展--空间复杂度和时间复杂度

空间复杂度和时间复杂度 文章目录 空间复杂度和时间复杂度空间复杂度时间复杂度**评价排序算法****时间频度****什么是时间频度****忽略常数项****忽略低次项****忽略系数** **时间复杂度****什么是时间复杂度****计算时间复杂度的方法****常见的时间复杂度** **常见的时间复杂…

Weblogic(CVE-2017-10271)与 Struts2(s2-045) 反序列化漏洞复现

文章目录 Java 反序列化漏洞复现weblogic环境搭建漏洞复现 Struts2(s2-045)环境搭建漏洞复现**漏洞利用** Java 反序列化漏洞复现 weblogic Weblogic < 10.3.6 ‘wls-wsat’ XMLDecoder 反序列化漏洞&#xff08;CVE-2017-10271&#xff09; ​ Weblogic的WLS Security组…

【ARM CoreLink 系列 2 -- CCI-400 控制器简介】

文章目录 CCI-400 介绍DVM 机制介绍DVM 消息传输过程TOKEN 机制介绍 下篇文章&#xff1a;ARM CoreLink 系列 3 – CCI-550 控制器介绍 CCI-400 介绍 CCI&#xff08;Cache Coherent Interconnect&#xff09;是ARM 中 的Cache一致性控制器。 CCI-400 将 Interconnect 和coh…

SUMPRODUCT函数

SUMPRODUCT函数返回相应范围或数组的个数之和。 默认操作是乘法&#xff0c;但也可以执行加减除运算。 本示例使用 SUMPRODUCT 返回给定项和大小的总销售额&#xff1a; SUMPRODUCT 匹配项 Y/大小 M 的所有实例并求和&#xff0c;因此对于此示例&#xff0c;21 加 41 等于 62。…

pytorch中的词性标注_seq2seq_比较naive的示例

一、各种用法_查漏补缺&#xff1a; 1.关于numpy中的argmax的用法&#xff1a; numpy之argmax()函数 - 知乎 (zhihu.com) 具体看这篇文章够了 二、代码注释&#xff1a; 参考&#xff1a; Sequence Models and Long Short-Term Memory Networks — PyTorch Tutorials 2.0.…

【1++的数据结构】之map与set(二)

&#x1f44d;作者主页&#xff1a;进击的1 &#x1f929; 专栏链接&#xff1a;【1的数据结构】 文章目录 一&#xff0c;前言二&#xff0c;红黑树的概念及其性质三&#xff0c;红黑树的插入四&#xff0c;红黑树的验证五&#xff0c;map与set的封装红黑树迭代器的实现map重载…

qt 正则表达式

以上是正则表达式的格式说明 以下是自己写的正则表达式 22-25行 是一种设置正则表达式的方式&#xff0c; 29-34行 : 29行 new一个正则表达式的过滤器对象 30行 正则表达式 的过滤格式 这个格式是0-321的任意数字都可以输入 31行 将过滤格式保存到过滤器对象里面 32行 将验…

快人一步进入智能新纪元,《新程序员006》来了!

文 | 王启隆 曾浩辰 出品 | 《新程序员》编辑部 亲爱的 CSDN 以及《新程序员》的读者朋友们&#xff0c;金秋将至&#xff0c;《新程序员006&#xff1a;人工智能新十年》也正式与大家见面&#xff01;现在点击下方封面&#xff0c;即可订阅&#xff0c;立即阅读电子书。精美…

UNIX网络编程卷一 学习笔记 第三十章 客户/服务器程序设计范式

开发一个Unix服务器程序时&#xff0c;我们本书做过的进程控制&#xff1a; 1.迭代服务器&#xff08;iterative server&#xff09;&#xff0c;它的适用情形极为有限&#xff0c;因为这样的服务器在完成对当前客户的服务前无法处理已等待服务的新客户。 2.并发服务器&#x…

Java笔记040-反射/反射机制、Class类

目录 反射(reflection) 一个需求引出反射 反射机制 Java反射机制原理图 Java反射机制可以完成 反射相关的主要类 反射机制的优点和缺点 反射调用优化-关闭访问检查 Class类 基本介绍 代码解释部分 类加载方法 应用实例&#xff1a;Class02.java 获取Class类对象 …

【17 > 分布式接口幂等性】2. Update的幂等性原理解析

一、 根据 唯一业务号去更新 数据的情况 1.1 原理 1.2 操作 1.3 实战 Stage 1&#xff1a;表添加 version 字段 Stage 2&#xff1a;前端 > 版本号放入隐藏域 Stage 3&#xff1a;后台 > 使用版本号作为更新条件 二、更新操作没有唯一业务号&#xff0c;可使用Tok…

RP9学习-1

一.基础 1.10个面板位置示意图&#xff1a; 2.常用英文 1.鼠标点击&#xff1a;click or tap 3.工作区 1.恢复默认工作区&#xff1a; view-->reset view 2.自定义工作区&#xff1a; 可以用鼠标左键拖动面板到独立的位置或者吸附到其他面板上 3.自定义工具栏 view-->T…

Adobe Acrobat Reader界面改版 - 解决方案

问题 日期&#xff1a;2023年9月 Adobe Acrobat Reader下文简称Adobe PDF Reader&#xff0c;此软件会自动进行更新&#xff0c;当版本更新至2023.003.20284版本后。 软件UI界面会大改版&#xff1a;书签页变成了右边、工具栏变到了左边、缩放按钮变到了右下角&#xff0c;如…

打造高效的私密论坛网站:Cpolar内网穿透+HadSky轻量级搭建指南

文章目录 前言1. 网站搭建1.1 网页下载和安装1.2 网页测试1.3 cpolar的安装和注册 2. 本地网页发布2.1 Cpolar临时数据隧道2.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;2.3 Cpolar稳定隧道&#xff08;本地设置&#xff09;2.4 公网访问测试 总结 前言 经过多年的基础…

怎么激活IDM

IDM是一个下载软件。 激活它需要用到git上面的一个项目&#xff0c;同时网络要能连到github GitHub - lstprjct/IDM-Activation-Script: IDM Activation & Trail Reset Script WINR 输入powershell 输入命令行 iex(irm is.gd/idm_reset) 或者 iwr -useb https://raw.…