穷举深搜暴搜回溯剪枝(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.mzph.cn/news/75884.shtml

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

相关文章

海光异构智能计算专区上线飞桨AI Studio!

近日&#xff0c;海光异构智能计算专区正式上线飞桨AI Studio(星河社区)。专区内容来自官方发布和社区贡献&#xff0c;包含双方产品合作成果、行业解决方案、优秀项目展示等&#xff0c;致力于帮助开发者快速了解体验飞桨、为海光异构智能计算软硬协同优化带来更高性能提升。 …

Kafka3.0.0版本——消费者(消费者组原理)

目录 一、消费者组原理1.1、消费者组概述1.2、消费者组图解示例1.3、消费者组注意事项 一、消费者组原理 1.1、消费者组概述 Consumer Group&#xff08;CG&#xff09;&#xff1a;消费者组&#xff0c;由多个consumer组成。形成一个消费者组的条件&#xff0c;是所有消费者…

C#事件event

事件模型的5个组成部分 事件拥有者&#xff08;event source&#xff09;&#xff08;类对象&#xff09;&#xff08;有些书将其称为事件发布者&#xff09; 事件成员&#xff08;event&#xff09;&#xff08;事件拥有者的成员&#xff09;&#xff08;事件成员就是事件本身…

用python实现基本数据结构【04/4】

说明 如果需要用到这些知识却没有掌握&#xff0c;则会让人感到沮丧&#xff0c;也可能导致面试被拒。无论是花几天时间“突击”&#xff0c;还是利用零碎的时间持续学习&#xff0c;在数据结构上下点功夫都是值得的。那么Python 中有哪些数据结构呢&#xff1f;列表、字典、集…

2023高教社杯数学建模A题思路分析 - 定日镜场的优化设计

# 1 赛题 A 题 定日镜场的优化设计 构建以新能源为主体的新型电力系统&#xff0c; 是我国实现“碳达峰”“碳中和”目标的一项重要 措施。塔式太阳能光热发电是一种低碳环保的新型清洁能源技术[1]。 定日镜是塔式太阳能光热发电站(以下简称塔式电站)收集太阳能的基本组件&…

FastViT实战:使用FastViT实现图像分类任务(一)

文章目录 摘要安装包安装timm安装 grad-cam安装mmcv 数据增强Cutout和MixupEMA项目结构计算mean和std生成数据集补充一个知识点&#xff1a;torch.jit两种保存方式 摘要 论文翻译&#xff1a;https://wanghao.blog.csdn.net/article/details/132407722?spm1001.2014.3001.550…

mysql leetcode打题记录

文章目录 完成度基本语法高级语法连接日期 函数编写函数聚合函数 因为上过的数据库课实在太水了&#xff0c;所以打算先在菜鸟教程/CSDN/leetcode先学一下基本语法&#xff0c;然后去做Stanford数据库原理的课程CS145。 小目标&#xff1a;把leetcode上不用钱的mysql的题先做一…

企业密码安全:ADSelfService Plus 提升密码管理的千里之行

在当今数字化时代&#xff0c;企业的密码安全变得至关重要。密码是保护企业敏感信息和数据的第一道防线&#xff0c;而有效的密码管理对于确保网络安全至关重要。ADSelfService Plus是一款强大的密码管理和自助服务解决方案&#xff0c;它在提供密码安全方面走在了前沿。 ADSel…

【大数据之Kafka】十、Kafka消费者工作流程

1 Kafka消费方式 &#xff08;1&#xff09;pull&#xff08;拉&#xff09;模式&#xff1a;消费者从broker中主动拉取数据。&#xff08;Kafka中使用&#xff09; 不足&#xff1a;如果Kafka中没有数据&#xff0c;消费者可能会陷入循环&#xff0c;一直返回空数据。 &#…

Python自动化测试(1)-自动化测试及基本技术手段概述

生产力概述 在如今以google为首的互联网时代&#xff0c;软件的开发和生产模式都已经发生了变化&#xff0c; 在《参与感》一书提到&#xff1a;某位从微软出来的工程师很困惑&#xff0c;微软在google还有facebook这些公司发展的时候&#xff0c;为何为感觉没法有效还击&…

嵌入式基础知识-信息安全与加密

本篇来介绍计算机领域的信息安全以及加密相关基础知识&#xff0c;这些在嵌入式软件开发中也同样会用到。 1 信息安全 1.1 信息安全的基本要素 保密性&#xff1a;确保信息不被泄露给未授权的实体。包括最小授权原则、防暴露、信息加密、物理加密。完整性&#xff1a;保证数…

电容笔值不值得买?开学季比较好用的电容笔

眼看着新学期即将到来&#xff0c;到底应该选择什么样的电容笔&#xff1f;一款原装的苹果Pencil&#xff0c;就卖到了将近一千块&#xff0c;这对于很多人来说&#xff0c;都是一个十分昂贵的价格。事实上&#xff0c;由于平替电容笔的价格非常便宜&#xff0c;只要一二百元就…

【Spring Boot 源码学习】OnClassCondition 详解

Spring Boot 源码学习系列 OnClassCondition 详解 引言往期内容主要内容1. getOutcomes 方法2. 多处理器拆分处理3. StandardOutcomesResolver 内部类4. getMatchOutcome 方法 总结 引言 上篇博文带大家从源码深入了自动配置过滤匹配父类 FilteringSpringBootCondition&#x…

尚硅谷大数据项目《在线教育之离线数仓》笔记007

视频地址&#xff1a;尚硅谷大数据项目《在线教育之离线数仓》_哔哩哔哩_bilibili 目录 第12章 报表数据导出 P112 01、创建数据表 02、修改datax的jar包 03、ads_traffic_stats_by_source.json文件 P113 P114 P115 P116 P117 P118 P119 P120 P121 P122【122_在…

小米13Pro/13Ultra刷面具ROOT后激活LSPosed框架微X模块详细教程

喜欢买小米手机&#xff0c;很多是因为小米手机的开放&#xff0c;支持root权限&#xff0c;而ROOT对普通用户来说更多的是刷入DIY模块功能&#xff0c;今天ROM乐园小编就教大家如何使用面具ROOT&#xff0c;实现大家日常情况下非常依赖的微X模块功能&#xff0c;体验微X模块的…

Redis原理:动态字符串SDS

&#xff08;课程总结自b站黑马程序员课程&#xff09; 一、引言 Redis中保存的Key是字符串&#xff0c;value往往是字符串或者字符串的集合。可见字符串是Redis中最常用的一种数据结构。 不过Redis没有直接使用C语言中的字符串&#xff0c;因为C语言字符串存在很多问题&…

DHTMLX Gantt 8.0.5 Crack -甘特图

8.0.5 2023 年 9 月 1 日。错误修复版本 修复 修复通过gantt.getGanttInstance配置启用扩展而触发的错误警告修复启用skip_off_time配置时gantt.exportToExcel()的不正确工作示例查看器的改进 8.0.4 2023 年 7 月 31 日。错误修复版本 修复 修复数据处理器不跟踪资源数据…

微信小程序slot插槽的介绍,以及如何通过uniapp使用动态插槽

微信小程序文档 - slots介绍 由上述文档看俩来&#xff0c;微信小程序官方并没有提及动态插槽内容。 uniapp文档 - slots介绍 uni官方也未提及关于动态插槽的内容 在实际使用中&#xff0c;直接通过 <<slot :name"item.xxx" /> 这种形式会报错&#xff…

23062C++QTday4

仿照string类&#xff0c;完成myString 类 代码&#xff1a; #include <iostream> #include <cstring> using namespace std; class myString {private:char *str; //记录c风格的字符串int size; //记录字符串的实际长度public://无参构造my…

分布式AKF拆分原则

目录 1 前言2 什么是AKF3 如何基于 AKF X 轴扩展系统&#xff1f;4 如何基于 AKF Y 轴扩展系统&#xff1f;5 如何基于 AKF Z 轴扩展系统&#xff1f;6 小结 1 前言 当我们需要分布式系统提供更强的性能时&#xff0c;该怎样扩展系统呢&#xff1f;什么时候该加机器&#xff1…