前端算法小白攻略42-leetcode(翻转二叉树)

140 阅读2分钟

「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战

前言

我们做过链表的翻转(链表的反转1,2),数组的翻转(煎饼排序),今天我们来做二叉树的翻转,原理都是一样的,操作略有一点不同。

题目描述

226. 翻转二叉树

给你一棵二叉树的根节点 root ,翻转这棵二叉树,并返回其根节点。

示例

image.png

输入: 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;
};