226. 翻转二叉树之多种解法(递归法、深度优先(迭代法)、广度优先【层序遍历】)

news2024/11/15 23:27:39

文章目录

  • 226. 翻转二叉树
  • 题外话
  • 思路
  • 递归法
  • 迭代法:深度优先遍历
  • 层序遍历:广度优先遍历
  • 拓展
  • 总结

226. 翻转二叉树

226. 翻转二叉树

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

示例 1:
在这里插入图片描述

输入:root = [4,2,7,1,3,6,9]
输出:[4,7,2,9,6,3,1]

示例 2:

在这里插入图片描述

输入:root = [2,1,3]
输出:[2,3,1]

示例 3:

输入:root = []
输出:[]

提示:

  • 树中节点数目范围在 [0, 100] 内
  • -100 <= Node.val <= 100

题外话

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

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

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

思路

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

这得怎么翻转呢?

如果要从整个树来看,翻转还真的挺复杂,整个树以中间分割线进行翻转,如图:
在这里插入图片描述

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

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

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

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

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

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

递归法

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

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

首先翻转根节点的左右子树,翻转前如下
在这里插入图片描述
翻转后如下
在这里插入图片描述
注意:现在4的左孩子是7而不是2了,继续递归遍历4的左孩子,便是遍历7的左右子树了,翻转前如下
在这里插入图片描述
翻转后如下
在这里插入图片描述
当左子树全部遍历完成后,才会去遍历右子树,即递归遍历2,然后翻转2的左右子树,最终翻转结束,回归到递归最开始的入口调用处。

我们来看一下递归三部曲

  1. 确定递归函数的参数和返回值
    参数就是要传入节点的指针,不需要其他参数了,通常此时定下来主要参数,如果在写递归的逻辑中发现还需要其他参数的时候,随时补充。返回值的话其实也不需要,但是题目中给出的要返回root节点的指针,可以直接使用题目定义好的函数,所以就函数的返回类型为*TreeNode
func invertTree(root *TreeNode) *TreeNode {}
  1. 确定终止条件
    当前节点为空的时候,就返回
if root == nil {
        return nil
    }
  1. 确定单层递归的逻辑
    因为是前序遍历,所以先进行交换左右孩子节点,然后递归翻转左子树,左子树全部递归完成,回归到对应的递归层后,再递归翻转对应层的右子树。
	// 前序遍历
    root.Left,root.Right = root.Right,root.Left
    if root.Left != nil {
        invertTree(root.Left)
    }
    if root.Right != nil{
        invertTree(root.Right)
    }

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

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func invertTree(root *TreeNode) *TreeNode {
    // 递归的翻转每个节点的左右孩子便会完成整棵树的翻转
    if root == nil {
        return nil
    }

    // 前序遍历
    root.Left,root.Right = root.Right,root.Left
    if root.Left != nil {
        invertTree(root.Left)
    }
    if root.Right != nil{
        invertTree(root.Right)
    }

    return root
}

在这里插入图片描述

迭代法:深度优先遍历

二叉树:之前已经介绍过二叉树的前中后三种遍历方式的迭代法了,这里不赘述啦,可以很轻松的写出如下迭代法的代码:

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func invertTree(root *TreeNode) *TreeNode {
    if root == nil {
        return nil
    }

    stack := make([]*TreeNode,0)
    stack = append(stack,root)
    for len(stack) > 0 {
        curNode := stack[len(stack) - 1]
        stack = stack[0:len(stack) - 1]
        curNode.Left,curNode.Right = curNode.Right,curNode.Left
        // 注意前序遍历,是先让右节点入栈,这样才能保证右节点后遍历
        if curNode.Right != nil {
        stack = append(stack,curNode.Right)
        }
        if curNode.Left != nil{
            stack = append(stack,curNode.Left)
        }
    }
    
    return root
}

在这里插入图片描述

层序遍历:广度优先遍历

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

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func invertTree(root *TreeNode) *TreeNode {
    if root == nil {
        return nil
    }

    queue := make([]*TreeNode,0)
    queue = append(queue,root)
    for len(queue) > 0 {
        queueSize := len(queue)
        for i := 0;i < queueSize ;i++ {
            curNode := queue[0]
            queue = queue[1:]
            // 翻转当前节点的左右孩子
            curNode.Left,curNode.Right = curNode.Right,curNode.Left
            if curNode.Left != nil {
                queue = append(queue,curNode.Left)
            }
            if curNode.Right != nil {
                queue = append(queue,curNode.Right)
            }
        }
    }

    return root
}

在这里插入图片描述

拓展

文中我指的是递归的中序遍历是不行的,因为使用递归的中序遍历,某些节点的左右孩子会翻转两次。

如果非要使用递归中序的方式写,也可以,如下代码就可以避免节点左右孩子翻转两次的情况:

/**
 * Definition for a binary tree node.
 * type TreeNode struct {
 *     Val int
 *     Left *TreeNode
 *     Right *TreeNode
 * }
 */
func invertTree(root *TreeNode) *TreeNode {
    // 递归的翻转每个节点的左右孩子便会完成整棵树的翻转
    if root == nil {
        return nil
    }

    if root.Left != nil { // 左
        invertTree(root.Left)
    }
	root.Left,root.Right = root.Right,root.Left // 中
    if root.Left != nil{ // 注意 这里依然要遍历左孩子,因为中间节点已经翻转了
        invertTree(root.Left)
    }

    return root
}

代码虽然可以,但这毕竟不是真正的递归中序遍历了。

总结

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

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

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

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

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2155173.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【JAVA开源】基于Vue和SpringBoot的在线文档管理系统

本文项目编号 T 038 &#xff0c;文末自助获取源码 \color{red}{T038&#xff0c;文末自助获取源码} T038&#xff0c;文末自助获取源码 目录 一、系统介绍二、演示录屏三、启动教程四、功能截图五、文案资料5.1 选题背景5.2 国内外研究现状5.3 可行性分析 六、核心代码6.1 查…

单片机原理及应用详解

目录 1. 什么是单片机&#xff1f; 2. 单片机的基本组成 3. 单片机的工作原理 4. 常见的单片机分类 5. 单片机的应用领域 6. 单片机开发流程 7. 单片机开发中的常见问题及解决方案 8. 单片机的未来发展趋势 9. 总结 1. 什么是单片机&#xff1f; 单片机&#xff08;Mi…

美食共享圈:Spring Boot校园周边美食平台

第二章 系统分析 2.1 可行性分析 可行性分析的目的是确定一个系统是否有必要开发、确定系统是否能以最小的代价实现。其工作主要有三个方面&#xff0c;分别是技术、经济和社会三方面的可行性。我会从这三个方面对网上校园周边美食探索及分享平台进行详细的分析。 2.1.1技术可行…

springboot实战学习笔记(5)(用户登录接口的主逻辑)

接着上篇博客学习。上篇博客是已经基本完成用户模块的注册接口的开发以及注册时的参数合法性校验。具体往回看了解的链接如下。 springboot实训学习笔记&#xff08;4&#xff09;(Spring Validation参数校验框架、全局异常处理器)-CSDN博客文章浏览阅读576次&#xff0c;点赞7…

[云服务器13] 如何正确选择云服务器?

【非广告&#xff0c;仅提供建议&#xff0c;没有强制消费引导】 这期我们不讲搭建教程了&#xff0c;因为我想到前面12篇的教程&#xff0c;有关套餐配置的教程好像都有点敷衍…… 所以这期我们主要来说一说服务器的配置选择和不同配置的应用场景。 网站: 雨云 打开后&…

Cisco 基础网络汇总

⭕个人主页 可惜已不在 ⭕可以分享给身边有需要的人 ⭕有用的话就留下一个三连吧 目录 前言: 一.网络及网络设备认识 二. 二层网络 三. 生成树、端口 四. 三层网络 五.访问控制 六.NAT 七.DHCP 八.PPP 九.帧中继 十.热备份 十一.综合实验 十二.WLAN 十三.Cisco P…

Compiler Explorer 开源项目-在线编译器网站

Compiler Explorer 开源项目&#xff0c;一个交互式编译器探索网站。在 C、C、C♯、F♯、Rust、Go、D、Haskell、Swift、Pascal、ispc、Python、Java 或其他 30 多种支持的语言组件中编辑代码&#xff0c;并实时查看不同编译器&#xff08;包括不同cpu架构&#xff09;编译后的…

STM32—MPU6050

1.MPU6050简介 MPU6050是一个6轴姿态传感器可以测量芯片自身X、Y、Z轴的加速度、角速度参数&#xff0c;通过数据融合&#xff0c;可进一步得到姿态角&#xff0c;常应用于平衡车、飞行器等需要检测自身姿态的场景3轴加速度计(Accelerometer&#xff1a;测量X、Y、Z轴的加速度3…

构建未来企业的理论基石:业务能力建模指南的深度解析与战略实施框架

数字化转型已经成为全球企业的战略焦点&#xff0c;在这个过程中&#xff0c;如何有效地将复杂的业务需求、技术架构和市场变化结合&#xff0c;形成具备长期竞争力的企业能力框架&#xff0c;是企业成败的关键。《业务能力指南》提供了一套经过验证的理论体系&#xff0c;帮助…

数字图像面积计算一般方法及MATLAB实现

一、引言 在数字图像处理中&#xff0c;经常需要获取感兴趣区域的面积属性&#xff0c;下面给出图像处理的一般步骤。 1.读入的彩色图像 2.将彩色图像转化为灰度图像 3.灰度图像转化为二值图像 4.区域标记 5.对每个区域的面积进行计算和显示 二、程序代码 %面积计算 cle…

《COMMA: Co-articulated Multi-Modal Learning》中文校对版

系列论文研读目录 文章目录 系列论文研读目录摘要导言相关工作视觉语言模型提示学习视觉语言模型中的提示学习 方法准备工作提议方法 实验基准设定基础到新的概括跨数据集传输消融实验 结论 摘要 经过预训练的大规模视觉语言模型&#xff08;如CLIP&#xff09;已经在一系列下…

PyQt5 导入ui文件报错 AttributeError: type object ‘Qt‘ has no attribute

问题描述&#xff1a; 利用 PyQt5 编写可视化界面是较为普遍的做法&#xff0c;但是使用全新UI版本的 Pycharm 修改之前正常的UI文件时&#xff0c;在没有动其他代码的情况下发现出现以下报错 AttributeError: type object Qt has no attribute Qt::ContextMenuPolicy::Defaul…

BFS 解决多源最短路问题

文章目录 多源BFS542. 01 矩阵题目解析算法原理代码实现 1020. 飞地的数量题目解析算法原理 1765. 地图中的最高点题目解析算法原理代码实现 1162. 地图分析题目解析算法原理代码实现 多源BFS 单源最短路&#xff1a; 一个起点、一个终点 多源最短路&#xff1a; 可以多个起点…

Apache ZooKeeper 及 Curator 使用总结

1. 下载 官网地址&#xff1a;Apache ZooKeeper 点击下载按钮 选择对应的版本进行下载 2. 使用 1、解压 tar -zxf apache-zookeeper-3.9.2-bin.tar.gz2、复制配置文件&#xff0c;有一个示例配置文件 conf/zoo_sample.cfg&#xff0c;此文件不能生效&#xff0c;需要名称为…

LeetCode_sql_day31(1384.按年度列出销售总额)

目录 描述 1384.按年度列出销售总额 数据准备 分析 法一 法二 代码 总结 描述 1384.按年度列出销售总额 Product 表&#xff1a; ------------------------ | Column Name | Type | ------------------------ | product_id | int | | product_name | var…

将sqlite3移植到arm开发板上:

一、下载源代码 sqlite3网址&#xff1a;https://www.sqlite.org/download.html 下载&#xff1a;sqlite-autoconf-3460100.tar.gz 二、解压 在Linux家目录下创建一个sqlite3文件夹&#xff0c;将压缩包复制到该文件夹下&#xff0c;再在该目录下打开一个终端&#xff0c;执行…

【机器学习】--- 决策树与随机森林

文章目录 决策树与随机森林的改进&#xff1a;全面解析与深度优化目录1. 决策树的基本原理2. 决策树的缺陷及改进方法2.1 剪枝技术2.2 树的深度控制2.3 特征选择的优化 3. 随机森林的基本原理4. 随机森林的缺陷及改进方法4.1 特征重要性改进4.2 树的集成方法优化4.3 随机森林的…

7-50 畅通工程之局部最小花费问题 (kruskal)

输入样例: 4 1 2 1 1 1 3 4 0 1 4 1 1 2 3 3 0 2 4 2 1 3 4 5 0输出样例: 3 代码&#xff1a; #include<iostream> #include<queue> using namespace std; const int N110; struct node{int x,y,w;bool operator <(const node &n1)const{if(wn1.w) retur…

4 html5 web components原生组件详细教程

web components 前面我们已经介绍过&#xff0c;这一期我们就来讲一讲具体用法和这其中的关键只是点&#xff1a; 1 基本使用 如果我们想实现一个封装的原生组件&#xff0c;那就离不开使用js去封装&#xff0c;这里主要就是基于HTMLElement这个类&#xff0c;去创建创建一个…

【HarmonyOS】深入理解@Observed装饰器和@ObjectLink装饰器:嵌套类对象属性变化

【HarmonyOS】深入理解Observed装饰器和ObjectLink装饰器&#xff1a;嵌套类对象属性变化 前言 之前就Observed和ObjectLink写过一篇讲解博客【HarmonyOS】 多层嵌套对象通过ObjectLink和Observed实现渲染更新处理&#xff01; 其中就Observe监听类的使用&#xff0c;Object…