2022年10月23日 10点57分
快速排序就是个二叉树的前序遍历,归并排序就是个二叉树的后序遍历
二叉树这种结构无非就是二叉链表,由于没办法简单改写成迭代形式,所以一般说二叉树的遍历框架都是指递归的形式
二叉树的所有问题,就是让你在前中后序位置注入巧妙的代码逻辑,去达到自己的目的,你只需要单独思考每一个节点应该做什么,其他的不用你管,抛给二叉树遍历框架,递归会在所有节点上做相同的操作。
二叉树题目的递归解法可以分两类思路,第一类是遍历一遍二叉树得出答案,第二类是通过分解问题计算出答案,这两类思路分别对应着 回溯算法核心框架 和 动态规划核心框架。
前中后序
void traverse(TreeNode root) {
if (root == null) {
return;
}
// 前序位置
traverse(root.left);
// 中序位置
traverse(root.right);
// 后序位置
}
前中后序的区别
中序位置主要用在 BST 场景中,你完全可以把 BST 的中序遍历认为是遍历有序数组
前序位置的代码只能从函数参数中获取父节点传递来的数据,而后序位置的代码不仅可以获取参数数据,还可以获取到子树通过函数返回值传递回来的数据。
一旦你发现题目和子树有关,那大概率要给函数设置合理的定义和返回值,在后序位置写代码了。
二叉树的最大深度
遍历解法
// 记录最大深度
int res = 0;
// 记录遍历到的节点的深度
int depth = 0;
// 主函数
int maxDepth(TreeNode root) {
traverse(root);
return res;
}
// 二叉树遍历框架
void traverse(TreeNode root) {
if (root == null) {
return;
}
// 前序位置
depth++;
if (root.left == null && root.right == null) {
// 到达叶子节点,更新最大深度
res = Math.max(res, depth);
}
traverse(root.left);
traverse(root.right);
// 后序位置
depth--;
}
分解解法
// 一棵二叉树的最大深度可以通过子树的最大深度推导出来,这就是分解问题计算答案的思路
// 定义:输入根节点,返回这棵二叉树的最大深度
int maxDepth(TreeNode root) {
if (root == null) {
return 0;
}
// 利用定义,计算左右子树的最大深度
int leftMax = maxDepth(root.left);
int rightMax = maxDepth(root.right);
// 整棵树的最大深度等于左右子树的最大深度取最大值,
// 然后再加上根节点自己
int res = Math.max(leftMax, rightMax) + 1;
return res;
}
层序遍历
二叉树题型主要是用来培养递归思维的,而层序遍历属于迭代遍历
BFS 算法框架 就是从二叉树的层序遍历扩展出来的,常用于求无权图的最短路径问题
有些很明显需要用层序遍历技巧的二叉树的题目,也可以用递归遍历的方式去解决,而且技巧性会更强
// 输入一棵二叉树的根节点,层序遍历这棵二叉树
void levelTraverse(TreeNode root) {
if (root == null) return;
Queue<TreeNode> q = new LinkedList<>();
q.offer(root);
// 从上到下遍历二叉树的每一层
while (!q.isEmpty()) {
int sz = q.size();
// 从左到右遍历每一层的每个节点
for (int i = 0; i < sz; i++) {
TreeNode cur = q.poll();
// 将下一层节点放入队列
if (cur.left != null) {
q.offer(cur.left);
}
if (cur.right != null) {
q.offer(cur.right);
}
}
}
}
前序遍历
226. 翻转二叉树
- 遍历解法
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
self.traverse(root)
return root
def traverse(self, root: Optional[TreeNode]):
if not root:
return
temp = root.left
root.left = root.right
root.right = temp
self.traverse(root.left)
self.traverse(root.right)
- 「分解问题」解法-递归
class Solution:
def invertTree(self, root: Optional[TreeNode]) -> Optional[TreeNode]:
if not root:
return root
left = self.invertTree(root.left)
right = self.invertTree(root.right)
root.left = right
root.right = left
return root
116. 填充每个节点的下一个右侧节点指针
- 三叉树解法【遍历】
class Solution:
def connect(self, root: 'Optional[Node]') -> 'Optional[Node]':
if not root:return root
def traverse(node1:'Optional[Node]',node2:'Optional[Node]'):
if not node1 or not node2:
return
# 将传入的两个节点穿起来
node1.next = node2
# 连接相同父节点的两个子节点
traverse(node1.left,node1.right)
traverse(node2.left,node2.right)
# 连接跨越父节点的两个子节点
traverse(node1.right,node2.left)
traverse(root.left,root.right)
return root
114. 二叉树展开为链表
递归解法
class Solution:
def flatten(self, root: Optional[TreeNode]) -> None:
"""
Do not return anything, modify root in-place instead.
"""
if not root:return
self.flatten(root.left)
self.flatten(root.right)
left = root.left
right = root.right
root.left = None
root.right = left
p = root
while p.right:
p = p.right
p.right = right
构造二叉树
-
- 从前序与中序遍历序列构造二叉树
-
- 从中序与后序遍历序列构造二叉树
-
- 根据前序和后序遍历构造二叉树
-
- 最大二叉树
2022年10月25日 09点09分