「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战」
前言
我们做过链表的翻转(链表的反转1,2),数组的翻转(煎饼排序),今天我们来做二叉树的翻转,原理都是一样的,操作略有一点不同。
题目描述
226. 翻转二叉树
给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。
示例
输入: root = [4,2,7,1,3,6,9]
输出: [4,7,2,9,6,3,1]
解题思路
我们根节点在翻转过程中是不会变的,翻转的都是根节点下的节点,结果返回root即可
递归法思路
从示例图中我们很容易可以看出,翻转二叉树其实就是递归反转根节点的左右子树,每颗子树的左右节点进行反转
迭代法思路
迭代法的重点在于,我们需要用数组来存放我们遍历的节点,每一次遍历翻转完当前一组节点后,同时需要生成下次遍历的子节点数组,我们每次遍历的都是一个新的数组
开始解题
递归法解题
这里的递归为了方便理解我分为两步实现,先对root子节点进行递归反转,再返回root
var invertTree = function(root) {
transfer(root);
return root;
};
var transfer = function (root) {
if(!root) return null; // 如果当前节点为空,那么就没有可反转的了
// 通过临时指针保存节点的方式进行反转节点,跟数组和链表一样的思想
let temp = root.right;
root.right = root.left;
root.left = temp;
// 节点反转的操作可以简化为 [root.right, root.left] = [root.left, root.right]
// 利用了数组的下标指针对节点的引用不会让节点被赋值之后丢失,从而进行节点的反转
transfer(root.left);
transfer(root.right);
}
迭代法解题
重点: while循环中当前节点的左右子节点交换完之后,所有不为空的节点都会放到统一的childArr中作为下个while循环的nodeArr
var invertTree = function(root) {
if(!root) return null;
let nodeArr = [root]; // root为节点数组中第一个要遍历反转的
while(nodeArr.length) {
let childArr = []; // 临时子节点数组
for(let i = 0; i < nodeArr.length; i++) {
// 遍历节点数组中的每个节点,只要当前节点存在左节点或右节点即可进行反转
if(nodeArr[i].left || nodeArr[i].right) {
[nodeArr[i].left,nodeArr[i].right] = [nodeArr[i].right,nodeArr[i].left];
}
// 当前节点的左右子节点反转完之后,不为空的子节点可以放到下次节点遍历反转数组中
nodeArr[i].left && childArr.push(nodeArr[i].left);
nodeArr[i].right && childArr.push(nodeArr[i].right);
}
nodeArr = childArr;
}
return root;
};