二叉树中的深搜算法介绍

1.计算布尔二叉树的值

2331. 计算布尔二叉树的值 - 力扣(LeetCode)https://leetcode.cn/problems/evaluate-boolean-binary-tree/description/ 给了一个二叉树,我们要以右边视角看待二叉树:

然后计算二叉树的结果,从叶子结点开始算:

下面来解决,用递归方式解决:先从宏观角度看:

盯着根结点看,想知道根这一层的结果,需要先知道左子树是T还是F,还要知道右子树是T还是F,这样才能知道自己是T还是F。要想知道左/右子树是T还是F,发现和我们的大问题是一样的,因此函数头是bool dfs(root),函数体是bool left = dfs(root->left),bool right = dfs(root->right),根据根与或情况来定。遇到叶子结点不用知道左右子树信息,返回叶子结点情况就行。下面来实现(左右子树可能为空,判断一下):

2.求根结点到叶子结点数字之和

129. 求根节点到叶节点数字之和 - 力扣(LeetCode)https://leetcode.cn/problems/sum-root-to-leaf-numbers/description/ (一条路径代表一个数字)如:

这道题用递归来解。(以某个位置在干嘛为突破口设计)首先我们要找到相同子问题,我们看递归到某一层是要干什么事情就能找出相同子问题。当我们递归到5这一层时,我们目标是拿到1258、12594、125931这几个数字。想算1258到这一层时,先把12传过来,要不然到这层只知道5和后面结点的信息,所以递归函数有个int类型参数。当到这一层时得到125(1),然后把125传到左边(2)和右边(3),从左边和右边分别拿到返回值相加。1.函数头 int dfs(root, int)。2.函数体(上述分析过程123)。3.递归出口:叶子结点。(在第一步执行完后判断一下叶子结点,左又子树可能为空判断一下)下面来实现:

3.二叉树剪枝

814. 二叉树剪枝 - 力扣(LeetCode)https://leetcode.cn/problems/binary-tree-pruning/description/ 也就是把都是0的子树全部移除,这道题是用递归,我们要重点搞定这样一些事情:1.函数头。2.函数体。3.递归出口。我们通过决策树模拟,抽象出递归的三个核心问题,如图:

当我递归到这一个位置时,我想关心这个东西是否被剪掉,我得先知道左子树的信息和右子树信息后才能得知是否减它。我想减它必须是左子树全为0,右子树全为0才能减它,可以感受到这道题一定是一个后序遍历。想到后序遍历后手这棵树模拟一下这个过程:

后序跑到0时左右为空都遍历完回到0时,这个节点左右为空,本身自己还是0,所以一定能被干了.干了后回到上一层1,回到上一层后要修改左子树的指针,因此左子树被干了,所以要把1的左树置为空。怎样才能回去时把1的左边置为空呢?返回值就可以,也就是0向上返回时把空返回去,然后1的left修改为返回值就行:

因此函数头设计时肯定有一个返回值。当1的左子树接收到空后,右子树也为空,返回到1这层后判断左子树为空,右子树为空,但我本身是1,所以不需要把这个节点干掉。继续向上往后,把1的根节点返回给上层(统一动作,因为每一层干的事情一样)。接下来遍历0的右子树:

此时就可以总结了,Node*dfs(root),我们这个函数仅需传根结点值就行。当把root传进去后,弄一下左子树,弄一下右子树,左边右边弄完分别返回,通过两个返回值就能决定当前结点是否删除。函数体:1.处理左子树 2.处理右子树 3.判断。递归出口:遇到空时直接返回空。下面来实现:

4.验证二叉搜索树

98. 验证二叉搜索树 - 力扣(LeetCode)https://leetcode.cn/problems/validate-binary-search-tree/description/ 二叉搜索树的中序遍历的结果,是一个有序的序列。如:

想到这个性质后可能会有这样的想法:弄一个数组,对这颗树来个中序遍历,把中序遍历结果填数组中,验证一下数组中的数是否是有序序列?但不敢这样写,空间消耗太大。但这样可以想到,我只要验证中序遍历是否有序就可以了。可以弄个全局变量prev,先初始化为负无穷。这个全局变量的意思是中序遍历过程中当遍历到某一个位置时,这个位置的前驱应该是多少。比如中序遍历到10的时候它的前驱是9,这样仅需拿10和9判断一下就行(能遍历到10说明前面判断过了)。因此解决方法是:中序遍历,当第一次到1的时候,1比负无穷大,比完后把prev更新为1,然后根据中序顺序向上传;7比1大,把prev改为7,然后中序遍历到9......当prev是20,20比19小,说明无序不是二叉搜索树。这道题可用全局变量+中序遍历来解决。我们有两种判断是否是二叉搜索树的方法,策略1:左子树是二叉搜索树,当前结点符合二叉搜索树的定义,右子树也是二叉搜索树(这是中序走到1回到7的时候就是回溯)。以上策略既要弄左子树,还要弄右子树,才判断我是不是二叉搜索树,其实不用这样麻烦:当prev是20,遍历到19这个结点时,我已经发现不是二叉搜索树了,这样没必要去右子树看看了,直接向上返回false就行,这就是剪枝(意义是加快我们搜索过程)。因此策略2:剪枝。下面来实现:

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

230. 二叉搜索树中第 K 小的元素 - 力扣(LeetCode)https://leetcode.cn/problems/kth-smallest-element-in-a-bst/description/ 两个全局变量+中序遍历。我们可以在中序遍历过程中弄个变量计数,当我遍历到第k个元素时用另一个变量标记一下最终结果就可以。如:

第一个变量是count,用来计数,初始化为6。中序遍历过程中每遍历一个结点就让count--,count减为0后那个结点就是我想要的结点。第二个变量ret,作用是当count减为0时ret标记当前结点的值,此时reg存的就是我要的结果。如何操作?刚开始中序遍历到4,此时让count--,然后中序到6;此时cont为4,不为0,中序遍历到7......当到17时,count--到0,说明到了第6个结点,然后把ret更新为17。当找到最终结果后,后面的结点再不用遍历了。下面来实现(count==0时可以直接返回):

6.二叉树的所有路径

257. 二叉树的所有路径 - 力扣(LeetCode)https://leetcode.cn/problems/binary-tree-paths/description/ 如图:

题目要求找路径,那就从根节点开始一直向下搜索,一边搜索一边记录路径,到叶子结点时说明找到了一个路径,然后用一个字符串数组存一下就行。那如何实现上述想法呢?此时如果引入全局变量可以用2个全局变量,第一个全局变量是一个字符串数组ret,遍历过程中发现叶子结点就往ret里面塞。第二个全局变量是字符串变量path,当我们在深度遍历的时候记录一下路径。也就是深度优先时刚开始path里是1->,然后是1->2->,到4是遇到叶子只添4:1->2->4,然后把path放到ret里。继续看:

这里完成后要回溯到上一层,到上一层后path里不能有4,因为走到5这层时仅需传1->2->,所以此时要恢复现场,当我在深度优先遍历过程中是会更改全局变量的,向上回溯到上一层时要把全局变量恢复成首次来这一层的样子,因此回溯到上一层时要把4砍了。这样函数返回过程中还要不停pop,但十分麻烦,叶子节点返回时只用把4干了,2这一层向上返回时要把2->干了,所以感觉全局path这里不太好用。这里这样设计:1.函数头 void dfs(root,path),这样恢复现场会变容易。这样刚开始进到1这层时path是1->,这层调dfs进入2这层时相当于重新创建了path变量,然后修改为1->2->,此时上一层切path不影响,这样最终向上回溯时函数帮我们恢复现场了,不用自己考虑了。2.函数体(只关心某一层干嘛),是叶子结点只填数字,不是叶子时填数字->,然后记录左边,记录右边。3.递归出口,引入剪纸枝:

当左子树为空时,就不需要dfs(root->left),就把空减了,直接if(root==nullptr)return相当于进入后啥也没干返回。下面实现:

相关推荐
zz34572981131 小时前
C语言中字符串常量存储位置
c语言·开发语言·算法·青少年编程
noipp1 小时前
推荐题目:洛谷 P16510 [GKS 2015 #C] gRanks
java·c语言·开发语言·c++·python·算法
菜菜的顾清寒1 小时前
力扣HOT100(50)动态规划-零钱兑换
算法·leetcode·动态规划
周末也要写八哥1 小时前
三分钟读懂:如何解决做题数量不足的问题?
算法
8Qi81 小时前
LeetCode 148. 排序链表 —— 解法二:自底向上归并(迭代,O(1) 空间)
数据结构·算法·leetcode·链表·归并·迭代
嘿黑嘿呦1 小时前
数据结构-图论-最小生成树
数据结构·算法·图论
Justice Young1 小时前
算法分析与设计实验:贪心法求解0/1背包问题的局限性
算法
黎阳之光1 小时前
无感定位·智管全域:黎阳之光人员无感定位管理系统,重新定义安全与效率
人工智能·物联网·算法·安全·数字孪生
小许同学记录成长2 小时前
网格简化算法 — Edge Collapse(边塌缩)
qt·算法