【递归、搜索与回溯】搜索

搜索

  • 1.计算布尔二叉树的值
  • 2.求根节点到叶节点数字之和
  • 3. 二叉树剪枝
  • 4.验证二叉搜索树
  • 5.二叉搜索树中第K小的元素
  • 6.二叉树的所有路径

在这里插入图片描述

点赞👍👍收藏🌟🌟关注💖💖
你的支持是对我最大的鼓励,我们一起努力吧!😃😃

1.计算布尔二叉树的值

题目链接:2331. 计算布尔二叉树的值

题目分析:

在这里插入图片描述

给一颗完整二叉树,孩子节点要么是0要么是2,不存在1个孩子节点。
叶子节点和非叶子节点数字分别代表不同的意思,最后将root根结果bool值返回去。

在这里插入图片描述
算法原理:

解法:递归
宏观角度看待递归
当想知道root根节点bool值时,我要先知道左子树bool值,在知道右子树bool值,然后将左右子数的bool值和root本身信息做整合。当我们要知道左子树和右子树的bool值,你会发现它和大问题是一样的。大问题是解决整棵树的bool值,小问题是解决左子树bool值,右子树bool值。此时把左指针传给dfs,dfs把左子树bool值给你,把右指针传给dfs,dfs把右子树bool值给你。所以dfs非常好设计。
函数头
bool dfs(TreeNode* root)

在这里插入图片描述
函数体也就出来了,先求左子树bool值,在求右子树bool,不要管递归如何执行,只需要知道你给它数据它一定能完成任务。
bool left=dfs(root->left)
bool right=dfs(root->right)
最后在将左子树和右子树bool值和root做整合。

递归出口 到叶子节点就不需要往后递归了,此时返回结果就行了

class Solution {
public:bool evaluateTree(TreeNode* root) {if(root->left == nullptr) return root->val == 0 ? false : true;bool left=evaluateTree(root->left);bool right=evaluateTree(root->right);return root->val == 2 ? left|right : left&right;}
};

2.求根节点到叶节点数字之和

题目链接:129. 求根节点到叶节点数字之和

题目分析:

在这里插入图片描述

将根到叶子节点组合的数加起来

在这里插入图片描述

算法原理:

解法:递归
首先我们要找到相同子问题,在树中相同子问题很好找,只需要关注递归到每一层需要干什么事情即可。当它们干的都是一样的事情,这就是相同的子问题。

当递归到5这一层,我发现要拿到和5相连下面的叶子节点的数把它们加起来,然后返回给根节点。当到5这一层

  1. 首先要把12先给我传过来,不然我怎么算出1258,也就是到某一层要把它之前路径上之后给我传过来。然后拿到这个12,先算出125。
  2. 然后把125传给左边
  3. 把125传给右边
  4. 然后把左边值的和与右边值的和相加,然后返回上一层节点

在这5这一层要完成4个任务,同理其他层也是要完成相同的任务。

在这里插入图片描述

1.函数头
首先要有一个返回值,就是传给dfs一个根节点把和它相连的叶子节点的和返回。但是要注意的是,我们除了要传一个根节点,还需要再把递归到该层的上面路径和拿到! 因此函数头是int dfs(root,presum)

2.函数体
1、2、3、4个步骤

3.递归出口
当到叶子节点就可以返回了,但是要注意的是,这个递归出应该在步骤1之后的,因为到叶子节点也要把叶子节点的数加上才向上返回的。

class Solution {
public:int sumNumbers(TreeNode* root) {return dfs(root,0);}int dfs(TreeNode* root,int presum){presum=presum*10+root->val;if(root->left == nullptr && root->right == nullptr)return presum;int ret=0;if(root->left) ret+=dfs(root->left,presum);if(root->right) ret+=dfs(root->right,presum);return ret;}
};

3. 二叉树剪枝

题目链接:814. 二叉树剪枝

题目分析:

在这里插入图片描述

注意这里的剪枝和前面说的剪枝是不一样的,前面的是那条路不是通往终点的路不能在走了,这里的剪枝真的就是把分枝剪掉!

返回移除了所有 不包含 1 的子树 的原二叉树 的意思是,就是如果子树全是0就把它剪掉。如果子数既有1又有0就不能剪掉。
在这里插入图片描述

算法原理:

通过决策树,抽象出递归的三个核心问题
也就是说通过,完成二叉树剪枝这个任务,完成递归三个核心问题。
像之前先把每个子问题要完成任务先找到,但是有时候某些道题非常麻烦,无法总结出子问题到底干了什么问题,这道题是给一个根节点然后把子树全为0剪掉然后把新根节点返回来。但是有些题特别抽象你根本无法总结出来你让这个递归去完成什么任务,任务太多了。此时我们要有一个能力,通过研究递归的过程来总结出函数头、函数体、递归出口!

在这里插入图片描述

首先这肯定是一个后序遍历,先要确定左右子树是什么情况才能决定是否把这个子树干掉。

当作后序遍历到底最左节点,然后再后序发现它左为空右为空,然后自己本身也是0,说明可以给它剪枝。然后回到上一层但是有一个问题,是不是要修改上一层左子树的指针啊,因此这个递归函数要有一个返回值 TreeeNode*。
在这里插入图片描述
然后如果左右子树都为空,但自己是1,说明不能剪枝
在这里插入图片描述
当我们把根左子树都弄好了,其实整个递归过程就出来。
在这里插入图片描述

  1. 函数头
    TreeNode* dfs(root) 给一个根节点,然后把结果给我
  2. 函数体
    左子树右子树都搞完返回给我一个东西,然后通过返回值在结合我自己看是否需要把自己删除。
    1.左子树、2.右子树、 3.判断
  3. 递归出口
    遇到null结束,就返回null
class Solution {
public:TreeNode* pruneTree(TreeNode* root) {if(root == nullptr) return nullptr;root->left=pruneTree(root->left);root->right=pruneTree(root->right);if(root->left == nullptr && root->right == nullptr && root->val == 0)return nullptr;else return root;}
};

4.验证二叉搜索树

题目链接:98. 验证二叉搜索树

题目描述:

在这里插入图片描述

算法原理:
这道题主要想说的有三个方面 1. 全局变量的优势 ,2. 回溯 ,3. 剪枝

这里我们利用一个性质,二叉搜索树的中序遍历结果,是一个有序的序列
可能你会想到用一个数组记录中序遍历的结果,然后在遍历一下数组。但是这样空间开销太大了。

我们还是利用这个性质解决这个问题,但是我们可以仅用一个全局变量就来判断这个中序遍历是否是有序的。这个全局变量是在中序遍历中当我遍历到某一个位置它的前序是多少。 并且因为是全局的,并不需要考虑在递归中如何传递,直接拿过来用就可以了!
在这里插入图片描述

当中序遍历到第一个节点后,比较该值和prev的大小,当前这个值比无穷小大说明当前中序遍历是有序的,就更新prev等于这个值。然后向上传,同理依旧是拿这个值和prev做比较等等,知道中序遍历到19发现这个值比prev要小,此时中序遍历就不是有序的,说明30左子树就不一颗二叉搜索树,也说明20右子树不是一颗二叉搜索树,进而说明整棵树就不是一颗二叉搜索树。直接返回即可!

在这里插入图片描述

所以这道题我们可以借助全局变量和中序遍历就可以解决这个问题。
我们有两种策略判断它是否是一个二叉树。
策略一:

  1. 左子树是一颗二叉搜索树,
  2. 当前节点也要符合二叉搜索树的定义
  3. 右子树也是一颗二叉搜索树

此时就颗树就是一颗二叉搜索树!

一个递归99%都有回溯,往上层返回就是回溯!
在这里插入图片描述

当前节点值的范围正好有INT_MIN,如果我们prev=INT_MIN 有可能第一层判断就有问题。因此把prev类型换一下,long 或者 long long

在这里插入图片描述

class Solution {
public:long prev=LONG_MIN;bool isValidBST(TreeNode* root) {if(root == nullptr) return true;bool left=isValidBST(root->left);bool cur=false;if(root->val > prev){prev=root->val;cur=true;}bool right=isValidBST(root->right);return left && cur && right;}
};

策略二:剪枝

当判断某棵子树不是二叉搜索树,整体就已经不是二叉搜索树了,就没有必要在去其他子树递归了,直接返回结果就行了。加快了我们的搜索过程
在这里插入图片描述
剪枝其实很简单,不要想的那么复杂。

class Solution {
public:long prev=LONG_MIN;bool isValidBST(TreeNode* root) {if(root == nullptr) return true;bool left=isValidBST(root->left);//剪枝if(left == false) return false;bool cur=false;if(root->val > prev){prev=root->val;cur=true;}//剪枝if(cur == false) return false;bool right=isValidBST(root->right);return left && cur && right;}
};

5.二叉搜索树中第K小的元素

题目链接:230. 二叉搜索树中第K小的元素

题目描述:

在这里插入图片描述

算法原理:

有了上面题的基础,这道题就非常简单了,仅需两个全局变量+中序遍历就行了

每次count-1,直到count==0,用ret记录结果。找到最终结果此时其他子树也不用遍历。也可以使用剪枝。

在这里插入图片描述

如果不使用全局遍历,就需要在递归函数中传参,并且还需要考虑参数在递归函数中如何改变。

class Solution {int count=0,ret=0;
public:int kthSmallest(TreeNode* root, int k) {count=k;dfs(root);return ret;// if(root == nullptr) return 0;// if(count <= k)//     kthSmallest(root->left,k);// ++count;// if(count == k)// {//     ret=root->val;// }// if (count <= k)//     kthSmallest(root->right,k);// return ret;}void dfs(TreeNode* root){if(root == nullptr || count == 0) return;dfs(root->left);--count;if(count == 0) ret=root->val;dfs(root->right);}
};

6.二叉树的所有路径

题目链接:257. 二叉树的所有路径

题目分析:

在这里插入图片描述

题目很简单,让找根到叶子节点的所有路径。

算法原理:
这道题重点强调的还是

  1. 全局变量
  2. 回溯
  3. 剪枝

其中这道题最重要的是想说回溯 ----> “恢复现场” ,一定纠正思想 因为出现了回溯 才会想到要 恢复现场

只要出现递归必定会有回溯,既然回溯中有恢复现场,那就可以这样说,只要有深度优先遍历就有恢复现场的操作。只不过在简单题恢复现场这个动作并不明显,因为参数在递归过程中就已经自动恢复现场了,但是在一些难的题里面,一旦用到全局变量,我们要手动恢复,这个恢复现场操作就会变成额外重要。

比如这道题我们用两个全局变量,path是把根到叶子节点所经历的路径记录下来,ret是把path到叶子节点后的整条路径记录下来。
在这里插入图片描述

path遇到不是叶子节点就 值 + ->,遇到叶子就把path放到ret数组中。但是此时有一个超级致命的问题,回溯的时候,path要回到上一层,你会发现回溯到上一层path不应该有 4 的,因为path往其他子树传仅需要传 1->2-> 就行了!那此时就应该 恢复现场把全局变量恢复下去之前的样子。此时还有一个问题如果把path设计成全局变量,回溯时path要不停pop,从叶子节点回溯还好说,但是从非叶子节点回溯要pop两次,挺麻烦的!

在这里插入图片描述

这道题用全局变量path记录路径比较麻烦,仅是这道题全局path不好用,但是比较麻烦的题全局path好用,这里只是为了说明,有恢复现场这个操作的。

这道题我们函数头这样设计 void dfs(root,path),把path当成参数传给函数,你会发现恢复现场特别容易,函数特性就已经帮我们恢复现场了。因为每次函数都会重新创建一个path,回溯到上一层用的还是上一层自己的path。就不用自己手动恢复了。

在这里插入图片描述

总结一下:全局变量 不好手动 恢复现场,那就 参数 自动 恢复现场

函数头,函数体都差不多了,接下来就是递归出口了,当root == nullptr 返回。但是这里递归还要进去才返回。此时我们可以剪枝,当非空进去,空就不要进!

在这里插入图片描述

class Solution {vector<string> ret;
public:vector<string> binaryTreePaths(TreeNode* root) {string path;dfs(root,path);return ret;}void dfs(TreeNode* root,string path){//if(root == nullptr) return;path+=to_string(root->val);if(root->left == nullptr && root->right == nullptr){ret.push_back(path);return;}path+="->";// dfs(root->left,path);// dfs(root->right,path);//回溯+剪枝 if就是剪枝if(root->left) dfs(root->left,path);//中间如果有就是回溯if(root->right) dfs(root ->right,path);}
};

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

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

相关文章

软件管理及部分命令

sed命令 格式&#xff1a; sed [选项] 操作 目标文件 选项&#xff1a; -i&#xff1a;修改原始文件【如果不加-i&#xff0c;那就是仅仅修改内存中的文件副本】 案例&#xff1a;将1.txt中的tom修改成jerry。 sed -i "s/tom/jerry/g" 1.txt 将1…

揭秘线程安全:HashMap 的四大实用策略

这篇文章&#xff0c;我们聊聊线程安全使用 HashMap 的四种技巧。 1 方法内部&#xff1a;每个线程使用单独的 HashMap 如下图&#xff0c;tomcat 接收到到请求后&#xff0c;依次调用控制器 Controller、服务层 Service 、数据库访问层的相关方法。 每次访问服务层方法 serv…

解决跨域的几种方法

解决跨域的方法主要有以下几种&#xff1a; 1.CORS&#xff08;跨域资源共享&#xff09; CORS是一种W3C规范&#xff0c;它定义了一种浏览器和服务器交互的方式来确定是否允许跨源请求。 服务器通过设置响应头Access-Control-Allow-Origin来允许或拒绝跨域请求。例如&#xf…

两站图片滑动对比效果实现(VUE3)

像这种图片滑动对比的效果&#xff0c;网上还不少见吧&#xff0c;但是网上却不好找到完整现成的实现代码&#xff0c;我找到几个地方有类似的代码&#xff0c;但是都不好直接移植到代码里&#xff0c;因为很多都是使用原生htmlcssjs实现&#xff0c;太复杂了。反而不好应用到v…

视觉SLAM十四讲:从理论到实践(Chapter12:建图)

前言 学习笔记&#xff0c;仅供学习&#xff0c;不做商用&#xff0c;如有侵权&#xff0c;联系我删除即可 一、主要目标 1. 理解单目SLAM中稠密深度估计的原理。 2. 通过实验了解单目稠密重建的过程。 3. 了解几种RGB-D重建中的地图形式。 构建的地图也有多种功能分类&…

DexCap——斯坦福李飞飞团队泡茶机器人:更好数据收集系统的原理解析、源码剖析

前言 2023年7月&#xff0c;我司组建大模型项目开发团队&#xff0c;从最开始的论文审稿&#xff0c;演变成目前的两大赋能方向 大模型应用方面&#xff0c;以微调和RAG为代表 除了论文审稿微调之外&#xff0c;目前我司内部正在逐一开发论文翻译、论文对话、论文idea提炼、论…

CSS实现3个圆点加载动画

加载动画主要使用了css的animation和transform属性&#xff0c;animation用来实现动画效果&#xff0c;transform实现过渡&#xff0c;让动画看起来更真实 一、html <div class"loadding-box"><div class"dot1"></div><div class&qu…

VCAST创建单元测试工程

1. 设置工作路径 选择工作目录,后面创建的 UT工程 将会生成到这个目录。 2. 新建工程 然后填写 工程名称,选择 编译器,以及设置 基础路径。注意 Base Directory 必须要为代码工程的根目录,否则后面配置环境会失败。 这样工程就创建好了。 把基础路径设置为相对路径。 …

解决Windows Hosts 文件因为权限无法修改的问题

如何修改 Windows Hosts 文件并添加域名映射 在日常工作中&#xff0c;可能需要修改 Windows 的 hosts 文件&#xff0c;以将特定的域名映射到指定的 IP 地址。本文介绍三种方法来完成这一任务&#xff1a;直接手动编辑 hosts 文件&#xff0c;使用批处理文件自动完成任务&…

【docker】 /bin/sh: ./mvnw: No such file or directory解决方案.dockerignore被忽略

报错如下&#xff1a;解决方案很简单&#xff0c;但是容易让大家忽视的问题。 > CACHED [stage-1 2/4] WORKDIR /work/ …

OpenCV学习(4.4) 平滑图像

1.目的 在本教程中将学习&#xff1a; 用各种低通滤波器模糊图像。对图像应用自定义过滤器&#xff08;二维卷积&#xff09;。 在图像处理中&#xff0c;平滑图像是一种去噪和模糊技术&#xff0c;用于减少图像中的噪声和细节&#xff0c;使得图像看起来更加平滑。平滑处理…

Java核心: 为图片生成水印

今天干了一件特别不务正业的事&#xff0c;做了一个小程序用来给图片添加水印。事情的起因是需要将自己的身份证照片分享给别人&#xff0c;手边并没有一个趁手的工具来生成图片水印。很多APP提供了水印的功能&#xff0c;但会把我的图片上传到他们的服务器&#xff0c;身份证太…

OpenCV的“画笔”功能

类似于画图软件的自由笔刷功能&#xff0c;当按住鼠标左键&#xff0c;在屏幕上画出连续的线条。 定义函数&#xff1a; import cv2 import numpy as np# 初始化参数 drawing False # 鼠标左键按下时为True ix, iy -1, -1 # 鼠标初始位置# 鼠标回调函数 def mouse_paint(…

冯喜运:6.7今日外汇黄金原油走势分析及日内操作策略

【黄金消息面分析】&#xff1a;美国初请失业金人数超预期&#xff0c;市场对美联储9月降息预期升温&#xff0c;全球降息潮起&#xff0c;黄金市场受支撑。北京时间本周四&#xff0c;美国劳工部公布的数据显示&#xff0c;截至6月1日当周初请失业金人数增加至22.9万人&#x…

docker-compose 最新详细安装教程

方法1.安装Compose单机版 此方法是网上大部分教程的办法&#xff0c;官方不提倡这种方法安装&#xff1a; curl -SL https://github.com/docker/compose/releases/download/v2.27.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose sudo chmod x /usr/local/…

Diffusers代码学习: IP-Adapter

从操作的角度来看&#xff0c;IP-Adapter和图生图是很相似的&#xff0c;都是有一个原始的图片&#xff0c;加上提示词&#xff0c;生成目标图片。但它们的底层实现方式是完全不一样的&#xff0c;我们通过源码解读来看一下。以下是ip adapter的实现方式 # 以下代码为程序运行…

BGP基础实验

BGP协议中的建邻&#xff0c;与宣告路由分开的 在任何一台BGP路由上&#xff0c;均可宣告本地路由表中通过任何形势获取的路由条目&#xff0c;将其共享给其他BGP邻居&#xff1b; 然后display ip rou查看 *>代表状态 *的意思是可用 >代表优 i和*>无关&#x…

【面试题-004】ArrayList 和 LinkList区别

文章目录 List和setArrayList扩容机制HashMap扩容机制HashMap初始容量&#xff08;Initial Capacity&#xff09;和负载因子&#xff08;Load Factor&#xff09;HashMap与HashTable区别 &#xff1f;HashMap底层数据结构&#xff1f;ConcurrentHashMap底层数据结构&#xff1f…

顶顶通呼叫中心中间件(mod_cti基于FreeSWITCH)-同振与顺振的用法

文章目录 前言联系我们实现步骤同振顺振 前言 什么是同振、顺振&#xff1f; 同振 &#xff1a;同振是指多个终端同时振铃顺振&#xff1a;顺振是指多个终端顺序振铃 联系我们 有意向了解呼叫中心中间件的用户&#xff0c;可以点击该链接添加工作人员的微信&#xff1a;顶顶…

Hi3519DV500 学习摘录

文章目录 一、问题1、open-vm-tools 安装2、pushd: not found3、autoreconf4、编译util-linux源码时报错 ERROR: You must have autopoint installed to 二、NFS1、服务器搭建2、u-boot常用命令3、配置4、问题 三、补缺1、make 一、问题 1、open-vm-tools 安装 open-vm-tools…