基本概念

除根节点之外每个节点只有一个父节点,根节点没有父节点;除叶节点之外所有节点都有一个或多个子节点,叶节点没有子节点。父节点和子节点之间用指针链接。

树的遍历

前序遍历:先访问根节点,再访问左子节点,最后访问右子节点。
中序遍历:先访问左子节点,再访问根节点,最后访问右子节点。
后序遍历:先访问左子节点,再访问右子节点,最后访问根节点。

这3种遍历都有 递归循环 两种不同的实现方法,每种遍历的 递归 实现都比 循环 实现要简洁很多。

例题

直接或间接考查遍历

面试题7“重建二叉树”
在这里插入图片描述

在前序遍历中,第一个是根节点;在中序遍历中,根节点的左边是左子树,右边是右子树。
可以 递归 地找到根节点和左右子树,从而重建二叉树。

面试题26“树的子结构”

在这里插入图片描述
这种题真是不适应。。。还没有把握好思路

遍历A ,找到与B相同的根节点的时候开始 遍历B ,看是否存在相同的子结构即可。

面试题27“二叉树的镜像”

在这里插入图片描述
这题还挺简单的,就相当于遍历一下这棵树,把左右子树对换一下就okk

面试题28“对称的二叉树”

在这里插入图片描述
这题好奇怪啊,明明可以直接用27题生成它的镜像然后看俩树是不是一样的,但好像生成镜像的时候原来那棵树也被镜像过去了。。。想偷懒没成啊 = =

思路其实挺简单的,但实现这个思路我觉得对我来说是个坎。

思路就是 遍历 两个树,一个是正常的前序遍历(中左右),另一个是对称的前序遍历(中右左),一直判断是不是相等就可以了。

为什么说实现思路是个坎呢?因为我确实一下子没想出来怎么搞。答案是新写一个参数有两棵树的函数。这里贴一下代码:

class Solution:
    def f(self, a, b):
        if a == None and b == None:
            return True
        if a == None or b == None:
            return False
        if a.val != b.val:
            return False
        return self.f(a.left, b.right) and self.f(a.right, b.left) 
        # 这块儿就是那个“对称”的体现了
    def isSymmetric(self, root: TreeNode) -> bool:
        return self.f(root,root)

面试题34“二叉树中和为某一值的路径”

在这里插入图片描述
这个题从逻辑上讲不难想,就是 前序遍历 一下这棵树, 每下一层就累加一下,每退一层就减回去,然后到 叶子节点 的时候看看和是不是等于那个值了,等于的话就添加到返回的list里,不等就拜拜然后返回上一层。主要是实现的过程,想清楚就好了。

面试题55“二叉树的深度”

在这里插入图片描述
有几种解法:

  1. 用面试题34“二叉树汇总和为某一值的路径”的方法,记录树中的所有路径,就能找到最大深度。
  2. 如果一棵树只有一个节点,那么它的深度为1。如果根节点只有左子树而没有右子树,那么树的深度应该是其左子树的深度加1;同样,如果根节点只有右子树而没有左子树,那么树的深度应该是其右子树的深度加1.如果既有右子树又有左子树,那么该树的深度就是其左、右子树深度的较大值再加1。用递归的方法就能解决实现
  3. 层次遍历,找到最深层

面试题55II“平衡二叉树”

在这里插入图片描述

  1. 在遍历树的每个节点的时候,得到它左、右子树的深度。如果每个节点的左、右子树的深度相差都不超过1,那么按照定义它就是一棵平衡二叉树。
  2. 如果我们用 后序遍历 的方式遍历二叉树的每个节点,那么在遍历到一个节点之前我们就已经遍历了它的左、右子树。只要在遍历每个节点的时候记录它的深度(某一节点的深度等于它到叶节点的路径的长度),我们就可以一边遍历一遍判断每个节点是不是平衡的。

面试题33“二叉搜索树的后序遍历序列”

宽度优先遍历

先访问树的第一层节点,再访问树的第二层节点……一直访问到最下面一层节点。在同一层节点中,以从左到右的顺序依次访问。

面试题32-I“从上到下打印二叉树-I”

在这里插入图片描述
这是个很基础的 宽度优先遍历 ,把每个节点的左右子树添加到 队列 里,按照队列顺序进行打印就行了。

面试题32-II“从上到下打印二叉树-II”

在这里插入图片描述
奇怪啊。。。这题明明比上面那个复杂,难度倒是变成了“简单”,可能因为有上面那个题作为基础,这题就显得简单了吧。。

跟上面那个题差不多,只不过每一层遍历的时候建个新的队列,遍历完老的队列之后用新的队列替换就行了。

面试题32-III“从上到下打印二叉树-III”

在这里插入图片描述
不对劲,这题应该也就变成简单了才对啊。。。

这比第二题就多了个标志位,每一行标志位取反就行了,然后按照标志位对应的顺序去输出。说起来,python这个list[::-1]真好使 - -

105.从前序与中序遍历序列构造二叉树

在这里插入图片描述
这题感觉应该是做过的,思路也很明确:

  1. 前序遍历的第一个就是根节点root
  2. 到中序遍历里找到这个根节点root
  3. 中序遍历里,root左边的m个是左子树,右边的n个是右子树
  4. 前序遍历里,root后边的m个是左子树,最后的n个是右子树
  5. 递归

把关键代码贴一下:

root = TreeNode()
root.val = r
root.left = self.buildTree(left_pre, left_ino)
root.right = self.buildTree(right_pre, right_ino)

106.从中序与后序遍历序列构造二叉树

在这里插入图片描述
这题跟上一题一个意思,就是前序遍历变成后序遍历了,根节点跑后续遍历的最后一个了,其他的基本相仿。贴个关键代码可以过了。

root = TreeNode()
root.val = r
root.left = self.buildTree(left_ino, left_pos)
root.right = self.buildTree(right_ino, right_pos)

二叉树的特例

二叉搜索树

左子节点总是小于或等于根节点,而右子节点总是大于或等于根节点。

面试题33“二叉搜索树的后序遍历序列”

在这里插入图片描述
这个题主要把握二叉搜索树的特点就可以了, 左子节点总是小于或等于根节点,而右子节点总是大于或等于根节点 。利用递归方法,遍历序列,找到满足条件的左右子树之后递归调用函数,判断左右子树分别是不是二叉搜索树,如果不是就返回False即可。

面试题36“二叉搜索树与双向链表”

在这里插入图片描述
这题基本思路很简单,但实现感觉逻辑上还是有点复杂呀。。

就是一个中序遍历,递归实现就可以了。每一次把 前后 两个节点的左右互连起来就好了。需要用两个额外的指针变量来保存。

这两天头脑不清楚,还是看了答案做的,所以把代码贴出来,感觉这种做法至少我一下子不能想的很清楚。

class Solution:
    def treeToDoublyList(self, root: 'Node') -> 'Node':
        def dfs(cur):
            if not cur: return
            dfs(cur.left) # 递归左子树
            if self.pre: # 修改节点引用
                self.pre.right, cur.left = cur, self.pre
            else: # 记录头节点
                self.head = cur
            self.pre = cur # 保存 cur
            dfs(cur.right) # 递归右子树
        
        if not root: return
        self.pre = None
        dfs(root)
        self.head.left, self.pre.right = self.pre, self.head
        return self.head
面试题54“二叉搜索树的第k大节点”

在这里插入图片描述
如果按照 中序遍历 的顺序遍历一颗二叉搜索树,则遍历序列的数值是 递增排序 的。中序遍历左中右 的顺序,这样出来是 递增 的,如果我们要找第 k k k大,可以用 递减 的序列,也就是用 右中左 的顺序去“中序遍历”

面试题68-I“二叉搜索树的最近公共祖先”

在这里插入图片描述
前序遍历 这棵树两次,分别遍历到p、q两个节点停止,保存两个节点的祖先路径,也就是两个列表,在这俩列表找到最近公共祖先就行了。遍历的时候要注意列表的进栈退栈,因为到了叶子节点的时候要返回,就要退栈,这个叶子节点显然不是祖先。然后这个题中是二叉搜索树,所以可以利用搜索树的 左小右大 特性进行遍历。

面试题68-II“二叉树的最近公共祖先-II”

在这里插入图片描述
与面试题68-I“二叉搜索树的最低公共祖先”的解法相同,只不过扩大范围到了普通的树,而不是搜索树了,遍历的时候利用不了这个特性了而已。

堆分为 最大堆最小堆

在最大堆中根节点的值最大,在最小堆中根节点的值最小。

红黑树

把树中的节点定义为红、黑两种颜色,并通过规则确保从根节点到叶节点的 最长路径 的长度不超过 最短路径 的两倍。

面试题40“最小的k个数”

其他例题

面试题37“序列化二叉树”

在这里插入图片描述
这题难度是 困难,一开始也觉得是真困难。。不过看了书感觉还是比较容易理解的。

序列化 :这个好说,想个办法给添加到list里就行了。最简单的就是前序遍历,然后注意None的时候也要添加进去,不然 反序列化 的时候不知道哪儿是根节点了。

反序列化 :这就有点讲究了,从原理上将也不麻烦,输入那个string类型的变量data,先变回list,然后挨个读,是数肯定就是个节点,是None那就是个叶子节点。因为是 前序遍历 出来的data,所以第一个肯定是根节点,然后后面连着的一段是 左子树 ,剩下那段就是 右子树。树的这些问题似乎都能使用递归来解决,只不过递归的时候注意要时刻维护着那个data,因为在不断 往前读

参考链接

1. https://leetcode-cn.com/circle/article/WTT5Yy/

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值