二叉树的遍历
94.二叉树的中序遍历
102.二叉树的层序遍历
103.二叉树的锯齿形层遍历
107.二叉树的层序遍历
199.二叉树的右视图
本质是层序遍历,并用容器记录最右边的值
二叉搜索树
方法:自下而上回溯,类似于归并排序。
最开始我使用的是自上而下的回溯。在整个过程中,发现递归终止条件难以判断,一时间陷入思维困境中。后来看了题解,才知道这道题目自上而下回溯是行不通的。
记忆化搜索。
- 定义一个数组
num[20]
,num[i]
表示由i个节点可以组成的二叉搜索树的种树。- 初始化:
num[0] =1;num[1] = 1;num[2] = 2
;- 计算公式: n u m [ i ] = ∑ i = 1 n n u m [ i − 1 ] × n u m [ n − i ] num[i] = \sum_{i = 1}^{n} num[i - 1] \times num[n - i] num[i]=∑i=1nnum[i−1]×num[n−i];
- 分别递归处理
num[i - 1]
和num[n - i]
。
方法:自下而上回溯。
- 递归处理左子节点和右子节点
- 判断当前节点的值是否大于左子节点以及小于右子节点,若不满足,返回
false
。- 判断当前节点的值是否大于左子树的最右下方节点以及小于右子树的最左下方节点,若不满足,返回
false
- 返回true
方法:中序遍历
- 中序遍历,将结果存在vector容器中。
- 正向遍历整个容器,寻找第一个不满足升序的数字
- 逆向遍历整个容器,寻找第一个不满足升序的数字
- 在树中查找上述两个数字,并交换
108.将有序数组转换为二叉搜索树
109.将有序链表转换为二叉搜索树
173.二叉搜索树迭代器
本题用到了二叉搜索树的迭代遍历算法。该算法的模板如下:
stack<TreeNode*> stk;
TreeNode* p = root;
while(p != nullptr || stk.size()){ // 这个判断条件要特别注意,很容易忘记
while(p != nullptr){ // 还有这个判断条件
stk.push(p); // 向栈里加入的是p,而不是p -> left
p = p -> left;
}
p = stk.top();stk.pop();
cout << p -> val << endl;
p = p -> next;
}
235.二叉搜索树的最近公共祖先
236.二叉树的最近公共祖先
- 先判断根节点是否等于p或
q
,- 接着递归,寻找
p
、q
的位置,返回值要么是nullptr
,要么是p
或q
的地址。- 最后根据返回值来判断它的公共祖先:
分情况讨论。
在删除的过程中,需要记录两个信息:待删除叶子节点以及待删除叶子节点的父节点。
若待删除节点是叶子节点,
- 待删除结点是根节点,返回
nullptr
- 待删除结点不是根节点,把父节点相应的子节点置
nullptr
。
若待删除节点的左子树是nullptr
- 待删除节点是根节点,返回待删除节点的右子树
- 把父节点相应的子树置为待删除节点的右子树
若待删除结点的右子树是nullptr
- 待删除节点是根节点,返回待删除结点的左子树
- 把父节点相应的子树置为待删除结点的左子树
若待删除结点左右子树都不为空,那么
- 寻找待删除节点左子树的最右下方结点(或右子树的最左下方结点,这里以左子树的最右下方结点为例)
- 交换待删除节点及其左子树的最右下方节点的值
- 按照待删除节点的右子树是
nullptr
的方法删除左子树最右下方的节点
与二叉树叶子节点相关
110和111这两道题目有点意思。
思路和算法:
- 深度优先遍历
- 广度优先遍历
- 位运算+二分查找
- 完全二叉树的特点是除最后一层外,其余各层的节点都完全填满;最后一层的节点按照从左到右的顺序依次填入。
- 规定根节点是第 0 0 0层,那么 h h h层的完全二叉树的节点数目落在区间 [ 2 h , 2 h + 1 − 1 ] [2^{h},2^{h+1}-1] [2h,2h+1−1]。因此我们可在该区间应用二分查找的方法得到完全二叉树节点的数目。
- 具体做法是,根据节点范围的上下界确定当前要判断的节点个数 k k k,若第 k k k个节点存在,二叉树的节点数目一定大于等于 k k k,反之小于 k k k。
- 如何判断第 k k k个节点是否存在?把 k k k写为二进制的形式(共 h + 1 h+1 h+1位),其中最高位一定是1,其余各位从高到底表示根节点到第 k k k个节点的路径: 0 0 0表示移动到左子节点, 1 1 1表示移动到右子节点。
方法:dfs,在递归的过程中维护一个路径,直到遍历到叶子节点把路径加入到答案中。
其他二叉树类型的题目
方法步骤如下:
- 判断两根指针是否非空,有四种情况:都空,都不空,只有一根指针非空。
- 判断当前两根指针指向内存的数据是否相
- 递归处理左子树和右子树
101.对称二叉树
104.二叉树的最大深度
105.从前序与中序遍历序列构造二叉树
106.从中序与后序遍历序列构造二叉树
114.二叉树展开为链表
方法:原地修改
116.填充每个节点的下一个右侧节点指针
117.填充每个节点的下一个右侧节点指针II
124.二叉树中的最大路径和
这道题目好难啊,我不会做
自上而下递归。每向下递归一层,和就要乘以10。
这道题目让我想起了297.二叉树的序列化和反序列化,它们的本质是一类题目。虽然本题不允许重建树,但是可以模拟树的建立过程,也就是说把反序列化代码中的树节点的创建过程去掉,然后按照反序列化代码的思路重做一遍本题。
划重点
- 无论是树,还是链表,凡是涉及到指针,第一步要判断该指针是否非空。