1、树的分类与特点
二叉树的左右子树都是二叉树,是用递归定义的,因此解决二叉树的许多问题都可以使用递归方法进行解决
- 二叉排序树的中序遍历就是树中接点按照顺序输出的顺序
做个总结,处理递归问题时:
- 将树当作
根
,左子树
,右子树
三部分,左子树、右子树具体是什么样的不管 - 找出终止条件,就是什么时候
return
,return
什么 - 只考虑当前这一步要完成什么功能
2、二叉树的常见技巧
二叉排序树往往可以采用中序遍历
对可以从非根节点开始的计算,往往可以采用递归的方式进行计算
求树中满足某个条件的所有组合时,往往需要采用回溯的算法
3、二叉树问题分类与分析
3.1、二叉树的遍历/查找(二叉树节点的和、二叉树的前中序)
- 往往需要递归的调用获取左子树和右子树的计算处理结果,然后再左右子树得到的结果上计算(`分析好如何通过左右子树得到计算结果,以及方法返回的是什么),有时附带着算需要计算的数据
- 计算任意子结构的某个值,往往需要定义一个
全局变量
,在遍历每个子结构的时候,对这个值可以进行一定的更新- DFS,BFS
- 二叉树的DFS遍历(递归与非递归版本):
借助栈实现,关键理解递归是如何实现的
- 二叉树的层序遍历(自顶向下):采用
BFS
的算法,利用一个队列
对逐层数据进行遍历 ,每次将队列
中的数据全部取出来,然后将取出来的数据的所对应的下一层节点再存入到队列
中,方便下层再取,最后将每层取出来的数据放入到list
链表的队尾即可。 - 在树的每行找到最大值
- 二叉树的层序遍历(自下向顶):
和上面的类似,只不过是遍历的时候,将每层取出来的数据放入到list链表的队首
- 二叉树的所有路径:
采用递归+回溯的方法
- 二叉树的深度:
方法1:
可以利用上面的层序遍历即可;方法2
:利用递归的方法,求每个节点左子树和右子树中深度的大值,再加上本层节点的1即可
二叉树递归之几个相似问题的分析–在递归树的时候统计树的某种特征
-
平衡二叉树:递归:当前节点的左右子树的深度差不大于1,并且左子树和右子树的左右子树的深度高度差不大于1
-
二叉树的直径:
首先要高清什么是二叉树的直径,任意两个节点路径长度中的最大值
;可以经过根也可以不经过根,因此在遍历的过程中需要定义一个全局变量,确保不断更新,获取 全局的值;分析可得 直径=Math.max(遍历过程中的上次直径,(左子树的深读+右子树的深度))
;而深度=Math.max(左子树的深度,右子树的深度)+1
-
最长的同值路径:
首先要搞清什么是同值路径,每个路径中的节点具有相同的值
;可以经过根也可以不经过根,在遍历的过程中需要定义一个全局变量,获得全局值;经过分析:先获取左侧最长路径长度,再获取右侧最长路径长度,在分析包含该节点的最长路径长度,更新双侧最长路径长度,更新单侧最长路径长度
;和上提类似 -
二叉树中的最大路径和:
求取二叉树节点(任意节点)的最大路径和,即抽取二叉树中任意连续节点的和的最大值,
与前两题类似,首先计算左子树的值,计算右子树的值,然后计算加上节点的最大值(定义一个全局变量进行保存),返回当前节点的最大值,从左右子树中挑一个最大的即可
-
给定二叉树的所有左叶子节点之和:
分析:遍历左子树,再遍历右子树,分析当前节点的左子节点是否存在,以及当前节点的左子节点是否为叶子节点如果则加上
-
路径之和求从根节点到叶子节点是否存在和为某个值:
递归遍历,若当前节点为叶子节点并且当前叶子节点的值为sum则返回true,否则遍历左右子节点
-
路径之和求任意两个节点之间的和等于某个值的所有路径:
双重递归,首先先序递归遍历每个节点,再以每个节点作为起始点递归寻找满足条件的路径
-
求根到叶子节点数字之和:
采用递归+回溯
3.2、二叉树的结构分析(深度、子结构)
- 一颗树是否为另一颗树的子树:
通过递归的方式解决
- 相同的树:
判断当前节点是否相等,以及当前节点的左子树是否相等且右子树是否相等
- 镜像二叉树:
什么是镜像的呢?分析树的结构,一个节点的左子节点以及右子节点是否相等,左子节点的左子树与右子节点的右子树相等并且左子节点的右子树与右子节点的左子树相等
- 叶子相似的树:通过中序遍历将树的叶子节点进行保存,然后比较两颗树的叶子节点即可。
3.3、排序二叉树(有特点的二叉树)
-
验证二叉搜索树:
中序遍历判断是否为递增数组
;通过dfs进行递归判断
-
二叉搜索树中的搜索:根据二叉搜索树的特点:如果当前节点为空则返回false,如果当前节点大于value则从左子树中查找,否则从柚子树中查找,若相等则找到
-
二叉搜索树中的插入操作:如果value<当前跟节点则插入到左子树中`root.left = insert(root.left,value);反之则可插入到右子树中,若相等则丢弃
-
二叉搜索树的最小绝对差:
二叉搜索树的中序遍历就是数据按照顺序输出的结果,因此可以在中序遍历的时候计算最小绝对差
-
二叉搜索树节点:
同上
-
二叉搜索树中的众数:
中序遍历,定义几个变量 计算之前遍历过程中众数出现的频次,遍历的过程中不断更新
-
二叉搜索树转为累加树:
二叉排序树的变形
-
二叉搜索树中的第k小节点:中序遍历,回去第
k
次遍历到的数据即可 -
修剪二叉搜索树,根据要求对二叉树进行修剪:递归:抓住二叉搜索树特点,若当前节点比left大则只能从右子树中找,若当前节点比R小则只能从左子树中找;处理正常的节点root.left = trimBST(root.left, L, R); root.right = trimBST(root.right, L, R);
-
特殊二叉树的第二小的节点:抓住特点:根节点的值不大于它的子节点,那么最小值只能出现在树的上部,次小的值只能出现在根的两个左右子树中,如果左右节点都大于根节点,那么次小的值出现在左右子树的Min(left,right),若左右节点有一个等于根节点,那么慈孝值只能为另一个树中
-
二叉搜索树的最近公共祖先:从根节点开始遍历,若两个节点都小于当前接节点则递归左子树,若两个节点都大于当前节点则从右子树开始递归,若一个在左子树一个在右子树则返回当前节点即可
3.4、树的重建
- 翻转二叉树:
采用深度和广度优先搜所进行操作
- 合并二叉树:采用递归:采用哨兵机制可以解决很多问题,合理使用哨兵机制,在原有的树的基础上进行合并,比如合并到树1上,如果树1中的节点为空,则将树2中节点的值复制到这个位置;如果树2中节点为空,则保留树1中的节点;若两个节点都不为空,则相加;然后再合并两个节点的左子树和右子树;对当前节点怎么处理以及对当前节点的子树如何处理是递归的关键
- 递增顺序查找树:
我们在树上进行中序遍历,会将树中的节点之间重新连接而不使用额外的空间,具体的,当我们遍历到一个节点时,把它的左孩子设为空,并将其本身作为上一个遍历到的节点的右子树
- 将有序数组转换为二叉搜索树:
有序数组可以使用二分查找
- 将有序链表转换为二叉搜索树:
采用二分查找法:和数组的类似,将链表分为两部分,左边的为左子树,右边的为右子树
- 根据前序(后)序与中序遍历重构二叉树:在前序(后序)序列中确定根节点到中序序列中找到根节点的位置,则
中序序列的前面是左子树,在其右面的是右子树,则可采用分治算法与递归接着处理
- 二叉树转换为链表:
递归的方法,先处理左子树,再处理右子树为链表
- 填充每个节点的下一个右侧节点指针:可以采用
BFS
,也可以采用dfs,我们以当前节root点为起始,左右节点不断的深入下面,left节点不断往右走,right节点不断往左走,当这两个节点走到底后,整个纵深这段就完成了串联。