二叉树有很多经典算法题,今天我们就来看一下二叉树里的翻转问题。
力扣226,给了一棵二叉树,要将二叉树整体翻转。
分析:观察图中翻转前后的二叉树,我们不难发现,翻转过程中,只需要把每一个节点的左右子节点交换以下就可以了,但是我们应该以什么样的顺序来遍历二叉树呢?如果是前序遍历,我们从根节点开始,用递归的方法来交换根节点的左右子树,一直到叶子结点。如果是后序遍历,就先交换叶子结点,如果当前遍历到的节点的左右子树均已翻转,就只需要交换两棵子树位置,就可以完成二叉树的翻转。
前序遍历:
// 前序遍历交换左右子节点,自顶向下
function invertTree(root) {
if (root === null) {
return null;
}
// 交换左右子节点
let temp = root.left;
root.left = root.right;
root.right = temp;
invertTree(root.left);
invertTree(root.right);
return root;
}
后序遍历:
// 后序遍历交换左右子节点,最后再交换根节点的左右子树,自底向上
function invertTree(root) {
if (root === null) {
return null;
}
// 先交换叶子节点的位置
let left = invertTree(root.left);
let right = invertTree(root.right);
root.left = right;
root.right = left;
return root;
}
此外,层次遍历也可以实现翻转,先将二叉树的根节点放入队列,然后从队列中拿出节点,交换节点的左右子节点,如果交换后的左右子节点不为空,则将左右子节点放入队列,再拿出节点,交换左右子节点,迭代处理。
function invertTree(root) {
if (root === null) {
return null;
}
// 将二叉树节点放入队列中
const treeQueue = [root];
while (treeQueue.length !== 0) {
// 每次从队列中取出一个节点,并交换这个节点的左右子树
let temp = treeQueue.pop();
let left = temp.left;
temp.left = temp.right;
temp.right = left;
// 如果当前节点的左子树不为空,则放入队列等待后续处理
if (temp.left !== null) {
treeQueue.push(temp.left);
}
// 如果当前节点的右子树不为空,放入队列等待后续处理
if (temp.right) {
treeQueue.push(temp.right);
}
}
return root;
}
总结:
二叉树的经典算法问题主要考察的还是对二叉树前中后序三种遍历方法的掌握。建议多做多看多思考。