东哥手把手带你刷二叉树(第一期)mp.weixin.qq.com/s/izZ5uiWzT…
东哥手把手带你刷二叉树(第二期)mp.weixin.qq.com/s/OlpaDhPDT…
东哥手把手带你刷二叉树(第三期)mp.weixin.qq.com/s/LJbpo49qp…
题库:226、236、124、105、99、
总结:
刷完整个专题,再去做什么回溯、动规、分治专题,你就会发现只要涉及递归的问题,都是树的问题。而树的问题就永远逃不开树的递归遍历框架这几行破代码:
/* 二叉树遍历框架 */ void traverse(TreeNode root) { // 前序遍历 traverse(root.left) // 中序遍历 traverse(root.right) // 后序遍历 }写树的算法,关键思路如下:
把题目的要求细化,搞清楚根节点应该做什么,然后剩下的事情抛给前/中/后序的遍历框架就行了,我们千万不要跳进递归的细节里。
延伸:
回溯算法:前文回溯算法详解干脆直接说了,回溯算法就是个 N 叉树的前后序遍历问题,没有例外。比如 N 皇后问题
快速排序就是个二叉树的前序遍历,归并排序就是个二叉树的后序遍历(归并也算分治问题)
1、placeholder
翻转二叉树
lc_226
将交换左右子树的代码放在前序遍历的位置。
填充二叉树节点的右侧指针
重写 lc_116:给定完美二叉树。
- 很容易想到层序遍历:将每个节点的子节点放入队列,迭代 的取出。—> 但是这样不好确定每层的分界点。
- 采用普通的前序遍历,递归的在父节点将两个子节点连接。—> 两个子节点之间没有连接了。
- 带两个参数的前序遍历,在本节点与另一个节点连接,并对两个节点的四个子节点递归调用连接函数,两两相连。
二叉树展开为链表
重写 lc_114
- 法一:in-place递归,自底向上
用前序遍历,每遍历一个节点,就将上一个节点的右指针更新为当前节点。 :不行!原因就是我们把 1 的右指针指向 2,那么 1 的原本的右孩子就丢失了,也就是 5 就找不到了。
解决方法是,我们可以逆过来进行。
我们依次遍历 6 5 4 3 2 1,然后每遍历一个节点就将当前节点的右指针更新为上一个遍历的节点。
从遍历次序上可看出,采取的是后序遍历,且依次是右子树,左子树,根节点。
另外,还需利用一个全局变量 pre,保存上一个遍历的后续节点,更新当前根节点的右指针为 pre,左指针为 null。
private TreeNode pre = null;
public void flatten(TreeNode root) {
if (root == null) return;
flatten(root.right);
flatten(root.left);
root.right = pre;
root.left = null;
pre = root;
}
- 法二:迭代,自顶向下
先序遍历+栈,提前将孩子保存到栈中,以免丢失。由于栈是先进后出,所以我们先将右节点入栈。
先序遍历的顺序是 1 2 3 4 5 6。用pre保存上次遍历的先序节点。
public void flatten(TreeNode root) {
if (root == null) return;
Stack<TreeNode> s = new Stack<>();
s.push(root);
TreeNode pre = null;
while (!s.empty()){
//弹出当前节点
TreeNode curr = s.pop();
//真正的更新操作
if (pre != null){
pre.right = curr;
pre.left = null;
}
// 将右、左子树分别压栈,实际上等同于递归,由于栈后进先出,先压右节点
if (curr.right != null) s.push(curr.right);
if (curr.left != null) s.push(curr.left);
//while循环指针更新
pre = curr;
}
}
构造最大二叉树
lc_654
先序遍历。
- 对于根节点root,先找出最大值,作为val;
- 递归调用左右数组,求得左右子节点,作为left、right;
- 用上面的的参数构建根节点;
- 递归。
用前、中序遍历构造树
lc_105
- 先根据preOrder找出根节点;
- 分别在inOrder、preOrder数组中界定左右子树(inorder:根据上面求出的根节点值遍历即可求得根节点在inorder中的坐标
index;preorder根据index和 inorder的左边界即可求出左子树节点数量 —> preOrder左子树的最右坐标)——共需要四个边界值参数 - 递归,直至preOrder索引不符合条件。
用中、后序遍历构造树
lc_106
同上题。
寻找重复的子树
lc_652
要点:1)以我为根的二叉树长什么样?(可以需要-后序遍历) —— 二叉树的序列化
2)以其他节点为根的子树长什么样? —— HashMap存储