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

    文章

    2104

    浏览量

    73482
  • 代码
    +关注

    关注

    30

    文章

    4742

    浏览量

    68327
  • 二叉树
    +关注

    关注

    0

    文章

    74

    浏览量

    12311

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

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

收藏 人收藏

    评论

    相关推荐

    AIC3254要怎么做才能够做到反馈抑制呢?

    设计,连编译都无法通过。各位大侠,到底怎么办呢,期待各位大侠的帮助,谢谢了,万分感谢。AIC3254要怎么做,才能够做到反馈抑制呢?
    发表于 11-08 07:49

    ppc3安装后只有第一次打开才正常,关闭ppc3后第次打开,无论如何就进不去界面了,为什么?

    我上个月申请了ppc3的下载。现在安装后只有第一次打开才正常,才能够正常看到界面并登陆。如果关闭ppc3后第次打开,无论如何就进不去界面了。除非再重新安装一遍才能打开。 下面就是这个进不去的界面:
    发表于 10-22 07:23

    什么是默克尔(Merkle Tree)?如何计算默克尔根?

    01 默克尔的概念 默克尔(Merkle Tree)是一种特殊的二叉树,它的每个节点都存储了一个数据块的哈希值。哈希值是一种可以将任意长度的数据转换为固定长度的字符串的算法,它具有唯一性和不可
    的头像 发表于 09-30 18:22 587次阅读
    什么是默克尔<b class='flag-5'>树</b>(Merkle Tree)?如何计算默克尔根?

    怎么才能够将正弦波的直流分量取出?

    请教怎么才能够将正弦波的直流分量取出,(我用低通滤波之后噪声很大)
    发表于 09-19 06:13

    指电极上覆盖敏感材料的阻值计算

    覆盖的敏感材料厚度超出指厚度时计算电阻,是否可以视作指电极指间电阻多个周期串联后与超出指厚度部分敏感材料电阻并联
    发表于 07-05 14:48

    指MOSFET器件静电防护鲁棒性提升技巧

    栅极接地NMOS是一种广泛应用的片上ESD器件结构,为达到特定ESD防护等级,一般会采用多指版图形式来减小器件占用的芯片面积。但是,多指栅极接地NMOS在ESD应力作用下,各个指难于做到均匀
    的头像 发表于 06-22 00:50 474次阅读
    多<b class='flag-5'>叉</b>指MOSFET器件静电防护鲁棒性提升技巧

    Endpoint端点如何做才能够达到不需要PC端手动IN就将数据往上推送?

    您好,我想问一下Endpoint端点如何做才能够达到不需要PC端手动IN就将数据往上推送? 使用的是FX3芯片,其中我发现在鼠标HID范例中,它就是不需要电脑IN,只要在某一个GPIO口触发之后
    发表于 05-27 08:29

    tle9879 hall电机启动需要用手拨动一下才能转动怎么解决?

    才能够正常启动运转,否则就不转动。 已经试着调试过启动占空比,给定的速度,以及 pid参数,都不管用。 问下能够得到指点一下,感谢!
    发表于 03-28 07:58

    哈夫曼编码怎么算 哈夫曼编码左边是0还是1

    二叉树,将出现频率高的字符用较短的编码表示,而出现频率低的字符则用较长的编码表示。通过这种方式,可以实现对数据进行高效的编码和解码。 下面我们将详细介绍哈夫曼编码的算法过程。 统计字符频率 在进行哈夫曼编码前,首先需
    的头像 发表于 01-30 11:27 2555次阅读

    instance是何时翻转的?每次有多少instance在翻转

    在run dynamic vectorless IR时,instance是何时翻转的?每次有多少instance在翻转
    的头像 发表于 01-26 09:31 498次阅读
    instance是何时<b class='flag-5'>翻转</b>的?每次有多少instance在<b class='flag-5'>翻转</b>?

    简单分析火车的供电示意图

    不知你注意没有,火车的用电都是用一根电线,并不是和家庭用的电一样是两根电线。都知道电器要工作必须有两根电线才行,这样才能够构成一个回路,电流才能够流通。
    的头像 发表于 01-03 11:08 1918次阅读
    简单分析火车的供电示意图

    是什么导致RAM中的内存数据损坏?纠错码(ECC)如何修复位翻转

    引起的故障等。当这些情况发生时,RAM中存储的数据可能会发生位翻转或完全丢失。 在了解纠错码(ECC)如何修复位翻转之前,我们首先需要了解ECC的工作原理以及它在RAM中的应用。 ECC是“Error Correcting Code”的缩写,它是一种
    的头像 发表于 12-15 09:58 2103次阅读

    如何修改内核设备

    如何修改内核设备
    的头像 发表于 12-14 14:06 767次阅读
    如何修改内核设备<b class='flag-5'>树</b>

    堆的实现思路

    什么是堆? 堆是一种 基于树结构的数据结构,它是一棵二叉树 ,具有以下两个特点: 堆是一个完全二叉树,即除了最后一层,其他层都是满的,最后一层从左到右填满。 堆中每个节点都满足堆的特性,即父节点的值
    的头像 发表于 11-24 16:02 393次阅读
    堆的实现思路

    二叉树的定义

    型结构 是一类重要的 非线性数据结构 ,其中以二叉树最为常用,直观来看,是以分支关系定义的层次结构。型结构在客观世界中广泛存在,比
    的头像 发表于 11-24 15:57 1274次阅读
    <b class='flag-5'>树</b>与<b class='flag-5'>二叉树</b>的定义