0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何才能够翻转二叉树

新材料在线 来源:代码随想录 作者:程序员Carl 2021-09-01 11:45 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

这道题目是非常经典的题目,也是比较简单的题目(至少一看就会)。

但正是因为这道题太简单,一看就会,一些同学都没有抓住起本质,稀里糊涂的就把这道题目过了。

如果做过这道题的同学也建议认真看完,相信一定有所收获!

226.翻转二叉树题目地址:https://leetcode-cn.com/problems/invert-binary-tree/

翻转一棵二叉树。

这道题目背后有一个让程序员心酸的故事,听说 Homebrew的作者Max Howell,就是因为没在白板上写出翻转二叉树,最后被Google拒绝了。(真假不做判断,权当一个乐子哈)

思路我们之前介绍的都是各种方式遍历二叉树,这次要翻转了,感觉还是有点懵逼。

这得怎么翻转呢?

如果要从整个树来看,翻转还真的挺复杂,整个树以中间分割线进行翻转,如图:

可以发现想要翻转它,其实就把每一个节点的左右孩子交换一下就可以了。

关键在于遍历顺序,前中后序应该选哪一种遍历顺序?(一些同学这道题都过了,但是不知道自己用的是什么顺序)

遍历的过程中去翻转每一个节点的左右孩子就可以达到整体翻转的效果。

注意只要把每一个节点的左右孩子翻转一下,就可以达到整体翻转的效果

这道题目使用前序遍历和后序遍历都可以,唯独中序遍历不行,因为中序遍历会把某些节点的左右孩子翻转了两次!建议拿纸画一画,就理解了

那么层序遍历可以不可以呢?依然可以的!只要把每一个节点的左右孩子翻转一下的遍历方式都是可以的!

递归法对于二叉树的递归法的前中后序遍历,已经在二叉树:前中后序递归遍历详细讲解了。

我们下文以前序遍历为例,通过动画来看一下翻转的过程:

我们来看一下递归三部曲:

确定递归函数的参数和返回值

参数就是要传入节点的指针,不需要其他参数了,通常此时定下来主要参数,如果在写递归的逻辑中发现还需要其他参数的时候,随时补充。

返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就函数的返回类型为TreeNode*。

TreeNode* invertTree(TreeNode* root)

确定终止条件

当前节点为空的时候,就返回

if (root == NULL) return root;

确定单层递归的逻辑

因为是先前序遍历,所以先进行交换左右孩子节点,然后反转左子树,反转右子树。

swap(root-》left, root-》right);

invertTree(root-》left);

invertTree(root-》right);

基于这递归三步法,代码基本写完,C++代码如下:

class Solution {public:

TreeNode* invertTree(TreeNode* root) {

if (root == NULL) return root;

swap(root-》left, root-》right); // 中

invertTree(root-》left); // 左

invertTree(root-》right); // 右

return root;

}

};

迭代法深度优先遍历二叉树:听说递归能做的,栈也能做!中给出了前中后序迭代方式的写法,所以本地可以很轻松的切出如下迭代法的代码:

C++代码迭代法(前序遍历)

class Solution {public:

TreeNode* invertTree(TreeNode* root) {

if (root == NULL) return root;

stack《TreeNode*》 st;

st.push(root);

while(!st.empty()) {

TreeNode* node = st.top(); // 中

st.pop();

swap(node-》left, node-》right);

if(node-》right) st.push(node-》right); // 右

if(node-》left) st.push(node-》left); // 左

}

return root;

}

};

如果这个代码看不懂的话可以在回顾一下二叉树:听说递归能做的,栈也能做!。

我们在二叉树:前中后序迭代方式的统一写法中介绍了统一的写法,所以,本题也只需将文中的代码少做修改便可。

C++代码如下迭代法(前序遍历)

class Solution {public:

TreeNode* invertTree(TreeNode* root) {

stack《TreeNode*》 st;

if (root != NULL) st.push(root);

while (!st.empty()) {

TreeNode* node = st.top();

if (node != NULL) {

st.pop();

if (node-》right) st.push(node-》right); // 右

if (node-》left) st.push(node-》left); // 左

st.push(node); // 中

st.push(NULL);

} else {

st.pop();

node = st.top();

st.pop();

swap(node-》left, node-》right); // 节点处理逻辑

}

}

return root;

}

};

如果上面这个代码看不懂,回顾一下文章二叉树:前中后序迭代方式的统一写法。

广度优先遍历也就是层序遍历,层数遍历也是可以翻转这棵树的,因为层序遍历也可以把每个节点的左右孩子都翻转一遍,代码如下:

class Solution {public:

TreeNode* invertTree(TreeNode* root) {

queue《TreeNode*》 que;

if (root != NULL) que.push(root);

while (!que.empty()) {

int size = que.size();

for (int i = 0; i 《 size; i++) {

TreeNode* node = que.front();

que.pop();

swap(node-》left, node-》right); // 节点处理

if (node-》left) que.push(node-》left);

if (node-》right) que.push(node-》right);

}

}

return root;

}

};

如果对以上代码不理解,或者不清楚二叉树的层序遍历,可以看这篇二叉树:层序遍历登场!

总结针对二叉树的问题,解题之前一定要想清楚究竟是前中后序遍历,还是层序遍历。

二叉树解题的大忌就是自己稀里糊涂的过了(因为这道题相对简单),但是也不知道自己是怎么遍历的。

这也是造成了二叉树的题目“一看就会,一写就废”的原因。

针对翻转二叉树,我给出了一种递归,三种迭代(两种模拟深度优先遍历,一种层序遍历)的写法,都是之前我们讲过的写法,融汇贯通一下而已。

大家一定也有自己的解法,但一定要成方法论,这样才能通用,才能举一反三!

其他语言版本Java://DFS递归class Solution {

/**

* 前后序遍历都可以

* 中序不行,因为先左孩子交换孩子,再根交换孩子(做完后,右孩子已经变成了原来的左孩子),再右孩子交换孩子(此时其实是对原来的左孩子做交换)

*/

public TreeNode invertTree(TreeNode root) {

if (root == null) {

return null;

}

invertTree(root.left);

invertTree(root.right);

swapChildren(root);

return root;

}

private void swapChildren(TreeNode root) {

TreeNode tmp = root.left;

root.left = root.right;

root.right = tmp;

}

}

//BFSclass Solution {

public TreeNode invertTree(TreeNode root) {

if (root == null) {return null;}

ArrayDeque《TreeNode》 deque = new ArrayDeque《》();

deque.offer(root);

while (!deque.isEmpty()) {

int size = deque.size();

while (size-- 》 0) {

TreeNode node = deque.poll();

swap(node);

if (node.left != null) {deque.offer(node.left);}

if (node.right != null) {deque.offer(node.right);}

}

}

return root;

}

public void swap(TreeNode root) {

TreeNode temp = root.left;

root.left = root.right;

root.right = temp;

}

}

Python递归法:前序遍历:

class Solution:

def invertTree(self, root: TreeNode) -》 TreeNode:

if not root:

return None

root.left, root.right = root.right, root.left #中

self.invertTree(root.left) #左

self.invertTree(root.right) #右

return root

迭代法:深度优先遍历(前序遍历):

class Solution:

def invertTree(self, root: TreeNode) -》 TreeNode:

if not root:

return root

st = []

st.append(root)

while st:

node = st.pop()

node.left, node.right = node.right, node.left #中

if node.right:

st.append(node.right) #右

if node.left:

st.append(node.left) #左

return root

迭代法:广度优先遍历(层序遍历):

import collections

class Solution:

def invertTree(self, root: TreeNode) -》 TreeNode:

queue = collections.deque() #使用deque()

if root:

queue.append(root)

while queue:

size = len(queue)

for i in range(size):

node = queue.popleft()

node.left, node.right = node.right, node.left #节点处理

if node.left:

queue.append(node.left)

if node.right:

queue.append(node.right)

return root

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C++
    C++
    +关注

    关注

    22

    文章

    2122

    浏览量

    76710
  • 代码
    +关注

    关注

    30

    文章

    4941

    浏览量

    73147
  • 二叉树
    +关注

    关注

    0

    文章

    74

    浏览量

    12862

原文标题:你真的会翻转二叉树么?

文章出处:【微信号:xincailiaozaixian,微信公众号:新材料在线】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    【OK3506-S12Mini试用评测()】开发板SDK配置动态设备

    在配好的虚拟机的终端输入./build.sh bconfig,选择Kernal 进去之后选择图中选项(按Y确定) Defconfig name 需要在终端输入命令,才能得到需要写的名字。 动态设备的名字是在虚拟机中找到要用的的dts文件。
    发表于 11-19 17:09

    通过优化代码来提高MCU运行效率

    选择时间复杂度低的算法。 根据访问模式选择数据结构。频繁查找用哈希表,有序数据用二叉树等。 查表法:对于复杂的数学计算(如sin, log),或者协议解析,预先计算好结果存于数组中,用空间换时间
    发表于 11-12 08:21

    蜂鸟E203内核中断管理模块sirv_plic_man代码分析

    。 上面的代码生成一个二叉树结构来比较和选择具有最大优先级的挂起中断源及其ID。树状结构由级联比较器组成,每一层的比较器数量是前一层的一半。在的每一层,选择优先级最高的中断并传递到下一层,直到只剩下
    发表于 10-23 06:05

    请问rtt studio 的文件夹打红什么意思?

    rtt studio 的文件夹打红什么意思?而且文件夹里面实际是有文件的,但是浏览不出来。
    发表于 09-18 06:34

    在使用EZ-USB® FX3™ 设备时,上电后相机开始正常工作,但延时10s左右播放器才能够显示图像数据?为什么?

    在使用EZ-USB® FX3™ 设备时,上电后相机开始正常工作,但延时10s左右播放器才能够显示图像数据?这是由于固件中的某些设置问题吗?
    发表于 07-16 07:08

    亿纬锂能荣获杭集团2022-2024年度优秀供应商奖

    近日,亿纬锂能凭借卓越产品、可靠交付与优质服务荣获杭集团颁发的“2022-2024年度优秀供应商”奖。杭集团副总经理兼杭电器董事长金华曙、杭电器总经理兼杭博电机总经理李明辉出席
    的头像 发表于 07-15 09:00 767次阅读

    请问K230 V3.0版本烧录固件和使用IDE到底是烧录哪个啊?

    使用了官网给的两个镜像包 如图 烧录进去后,都没有显示CAN MV 只显示了如下图这个 打开IDE一直使用链接不到 期待结果和实际结果 烧录哪一个镜像包的才能够准确使用? 并且能够使用CAN MV IDE 进行开发
    发表于 04-29 07:27

    机器人看点:宇科技王兴兴回上海母校 加速商业化落地 宇机器人手租赁火爆

    给大家带来一些机器人的消息: 宇科技王兴兴回上海母校 加速商业化落地 日前,宇科技创始人王兴兴在接受媒体专访时候,介绍了公司的H1人形机器人的技术亮点及行业前景,H1人形机器人是首款能原地后翻出
    的头像 发表于 02-25 11:26 1774次阅读

    固定式读码器一般多少钱才能够买到质量好的?

    在探讨固定式读码器价格与质量的关系时,我们首先需要明确的是,固定式读码器作为自动化识别领域的重要设备,其价格受多种因素影响,包括但不限于品牌、型号、功能、性能以及市场供需状况等。因此,要买到质量好的固定式读码器,并非单纯以价格高低作为唯一衡量标准,而是需要综合考虑多个方面。一般来说,市场上固定式读码器的价格区间较为广泛,从几百元到数万元不等。对于追求性价比的
    的头像 发表于 02-14 13:51 764次阅读
    固定式读码器一般多少钱<b class='flag-5'>才能够</b>买到质量好的?

    使用TLV5616进行DAC数模转化,怎么才能够给其提供稳定精确地参考电压从而保证转换精度?

    我正在使用TI公司的TLV5616进行DAC数模转化,想请教大家怎么才能够给其提供稳定精确地参考电压从而保证转换精度?期待大家的经验分享。
    发表于 02-07 07:55

    科技在物联网方面

    的发展,对传感器的需求不断增加且要求越来越高,宇科技通过与传感器公司的合作,不断优化和拓展传感器技术在其机器人产品中的应用,使机器人能够更好地适应各种物联网场景下的感知需求,如在智能家居场景中感知房间
    发表于 02-04 06:48

    ADS1259初始化程序必须执行两次才能够初始化成功,为什么?

    最近在调试ADS1259这个片子,发现初始化程序必须执行两次才能够初始化成功,然后读出来的CONFIG0寄存器的最高位是“0”(官方文档上是“1”),不知道是什么原因,求TI工程师解答呀!
    发表于 01-10 12:41

    嵌入式学习-飞凌嵌入式ElfBoard ELF 1板卡-初识设备之设备组成和结构

    的name和value。在设备中,可描述的信息包括:一、CPU的数量和类别;、内存基地址和大小;三、总线和桥;四、外设连接;五、中断控制器和中断使用情况;六、GPIO控制器和GPIO使用情况;七
    发表于 01-08 08:32

    飞凌嵌入式ElfBoard ELF 1板卡-初识设备之设备组成和结构

    的name和value。在设备中,可描述的信息包括:一、CPU的数量和类别;、内存基地址和大小;三、总线和桥;四、外设连接;五、中断控制器和中断使用情况;六、GPIO控制器和GPIO使用情况;七
    发表于 01-07 09:16

    ADS1298采用怎样的平均方法才能够将高采样率的数据平均成低采样率后,相应的把噪声降下来?

    是非常小的。这也符合datasheet上8.1 Noise Measurements的描述; 我们现在的问题是:采用怎样的平均方法才能够将高采样率的数据平均成低采样率后,相应的把噪声降下来?
    发表于 01-07 06:53