题目
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
原题链接
思路
对于任意一个结点都是交换左右子树再返回头,所以可以设计一个递归函数来实现。
设计递归
递归含义
- 对于每一个结点
root,交换它的左子树和右子树,交换完成后返回二叉树头root。 - 如果
root为空或左右子树都为空就不用交换了。
递归过程
对于任意一个结点:
- 先递进去
左子树,左子树内部交换完毕。 - 回到
父结点,递进去右子树,右子树内部交换完毕。 - 回到
父结点,此时左右子树内部都已交换好了,交换左右子树,返回父结点给爷爷结点使用。
宏观视角
🔥交换过程是: 左子树内部交换->右子树内部交换->头交换左右子树,即左右头,所以是一个后序遍历的过程。
🌲从 root 开始,左子树一路递到底,然后归返回到父结点,再递进入右子树,再归返回到父结点。然后父结点交换左右子树,再返回父结点给爷爷结点使用,这就是宏观的过程。
💡值得注意的是,每次返回的结点必然是以这个结点为头的整棵树已经交换完毕的了,这一点需要明白。
手绘图解
为了加深印象,笔者将自己的理解输出成一张手绘图,如下:
代码
TypeScript
function invertTree(root: TreeNode | null): TreeNode | null {
// 头为空,不用交换子树,直接返回 root
if (!root) {
return root;
}
// 左右子树都为空,不用交换子树,直接返回 root
if (!root.left && !root.right) {
return root;
}
// 1. 来到左子树
// 左子树`递`进去直到叶子结点,返回叶子头,再到叶子父结点交换左右子树,返回叶子父..
// 最后返回`整棵左子树交换完毕`的头
const left = invertTree(root.left);
// 2. 从左子树回到父结点
// 3. 从父结点进入右子树
// 左子树交换完毕,交换右子树
const right = invertTree(root.right);
// 4. 从右子树回到父结点
// 左右子树各自内部的结点交换完毕,头结点的两棵子树开始交换
root.left = right;
root.right = left;
// root这棵树交换完毕,返回头给root的父级使用。
return root;
};