递归遍历
- 前序遍历:中左右
- 中序遍历:左中右
- 后序遍历:左右中
二叉树的遍历模板如下。
void traverse(TreeNode root) {
if (root == null) {
return;
}
// 前序位置
traverse(root.left);
// 中序位置
traverse(root.right);
// 后序位置
}
- 前序位置就是刚进入节点时的位置
- 中序位置就是刚遍历完左子树,即将开始遍历右子树的位置
- 后序位置就是遍历完节点的左右子树后,回到节点的位置。
这几个位置的意义一定要理解清楚,后续做题离不开这些。
104二叉树的最大深度
思路:在后序位置计算节点最大深度,最大深度为左右子树的最大深度。
public int maxDepth(TreeNode root) {
if(root==null) return 0;
int leftMax = maxDepth(root.left);
int rightMax = maxDepth(root.right);
return 1 + Math.max(leftMax,rightMax);
}
114 二叉树展开为链表
给你二叉树的根结点 root
,请你将它展开为一个单链表:
- 展开后的单链表应该同样使用
TreeNode
,其中right
子指针指向链表中下一个结点,而左子指针始终为null
。 - 展开后的单链表应该与二叉树 先序遍历 顺序相同。
示例 1:
输入: root = [1,2,5,3,4,null,6]
输出:[1,null,2,null,3,null,4,null,5,null,6]
示例 2:
输入: root = []
输出: []
示例 3:
输入: root = [0]
输出: [0]
提示:
- 树中结点数在范围
[0, 2000]
内 -100 <= Node.val <= 100
进阶: 你可以使用原地算法(O(1)
额外空间)展开这棵树吗?
思路:在后序位置处理节点,将节点的左子树放到右子树的位置,左子树置空;随后将原右子树拼接到现右子树的末尾。
在下面这张图中,(2,3,4)这颗树就是最小的操作树,因为它的子结点都是叶子节点了,它是第一个可以操作子结点的后序位置。
因此,只需要考虑怎么处理这颗树即可。
public void flatten(TreeNode root) {
if(root==null) return;
flatten(root.left);
flatten(root.right);
//后序位置
TreeNode left = root.left;
TreeNode right = root.right;
root.left = null;
root.right = left;
//把原右子树拼到现在右子树的末尾
TreeNode p = root;
while (p.right!=null){
p = p.right;
}
p.right = right;
}
层序遍历
按层遍历结点,即:
1-2-3-4-5-6-7
层序遍历的模板也需要记下来,非常重要。
class Solution {
public List<List<Integer>> levelOrder(TreeNode root) {
List<List<Integer>> res = new LinkedList<>();
if (root == null) {
return res;
}
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
// while 循环控制从上向下一层层遍历
while (!q.isEmpty()) {
//每层的前序位置
int sz = q.size();
List<Integer> level = new LinkedList<>();
//遍历该层结点
for (int i = 0; i < sz; i++) {
//按顺序处理节点
TreeNode cur = q.poll();
level.add(cur.val);
//节点处理完毕,将其子节点入队,需判空
if (cur.left != null)
q.offer(cur.left);
if (cur.right != null)
q.offer(cur.right);
}
res.add(level);
}
return res;
}
}
116 填充结点的右侧节点指针
给定一个 完美二叉树 ,其所有叶子节点都在同一层,每个父节点都有两个子节点。二叉树定义如下:
struct Node {
int val;
Node *left;
Node *right;
Node *next;
}
填充它的每个 next 指针,让这个指针指向其下一个右侧节点。如果找不到下一个右侧节点,则将 next 指针设置为 NULL
。
初始状态下,所有 next 指针都被设置为 NULL
。
示例 1:
输入: root = [1,2,3,4,5,6,7]
输出: [1,#,2,3,#,4,5,6,7,#]
解释: 给定二叉树如图 A 所示,你的函数应该填充它的每个 next 指针,以指向其下一个右侧节点,如图 B 所示。序列化的输出按层序遍历排列,同一层节点由 next 指针连接,‘#’ 标志着每一层的结束。
示例 2:
输入: root = []
输出: []
提示:
- 树中节点的数量在
[0, 212 - 1]
范围内 -1000 <= node.val <= 1000
进阶:
- 你只能使用常量级额外空间。
- 使用递归解题也符合要求,本题中递归程序占用的栈空间不算做额外的空间复杂度。
class Solution {
public Node connect(Node root) {
if(root==null) return root;
Queue<Node> q = new LinkedList<>();
q.offer(root);
while (!q.isEmpty()){
int len = q.size();
for (int i = 0; i < len; i++) {
Node temp = q.poll();
if(i<len - 1) temp.next = q.peek();
//子节点入队
if(temp.left!=null) q.offer(temp.left);
if(temp.right!=null) q.offer(temp.right);
}
}
return root;
}
}