代码随想录算法训练营DAY15|C++二叉树Part.2|102.二叉树的层序遍历、226.翻转二叉树、101. 对称二叉树

文章目录

  • 102.二叉树的层序遍历
    • 思路
    • 伪代码
      • 迭代法
      • 递归法
    • CPP代码
    • 拓展题
  • 226.翻转二叉树
    • 思路
    • CPP代码
  • 101. 对称二叉树
    • 伪代码
    • CPP代码

102.二叉树的层序遍历

力扣题目链接
文章讲解:102.二叉树的层序遍历

视频讲解:讲透二叉树的层序遍历 | 广度优先搜索 | LeetCode:102.二叉树的层序遍历

状态:能够回忆起来层序遍历是利用队列、然后用size来进行每一层应该弹出的元素个数。如果栈空了,循环结束,但是代码上怎么也写不完整;递归法的层序遍历还是有理解难度的,处理逻辑是配合depth的前序遍历。

思路

广度优先搜索来遍历一个二叉树,就是从左到右一层一层得去遍历二叉树。

那么需要借用一个辅助数据结构即队列来实现,队列先进先出,符合一层一层遍历的逻辑,而用栈先进后出适合模拟深度优先遍历也就是递归的逻辑。

在每个结点进行结果处理,也就是弹出队列放入结果集的时候,把它的左右孩子入栈

伪代码

迭代法

层序遍历的迭代法很简单

queue<TreeNode*> que;//一定要注意这里放入的是结点
vector<vector<int>> res;
if (root) que.push(root);
while (!st.empty()){int size = que.size(); //记录本层应该弹出的元素vector<int> vec; //用来临时存放该层的结果for (int i = 0; i < size; i++){TreeNode* node = que.front;que,pop();res.push_back(node->val);if(node->left) que.push(node->left); // 空结点不入队if(node->right) que.push(node->right); //空结点不如队}result.push_back(res);
}
return result;

递归法

由于其并不是把当前层遍历完再去遍历下一层的规则,所以层序遍历的递归法总体还是比较难懂的。

其实递归法本质上还是先一直到底,然后再往上返回,用树结构来理解递归会好很多

还有一个重点就是它的处理逻辑很像中左右的前序遍历

  • 确定参数和返回值:传参可以确定三个,结点信息、结果集、当前的深度(用于确定当前节点应该放在结果向量的哪个层次中)。其中结果集用引用传递,这样返回值可以为空。
void order(TreeNode* node, vector<int>& vec, vector<vector<int>>& res){}
  • 确定终止条件:如果遇到结点为空,退出迭代。
if (cur == nullptr) return;	//这是递归的基本情况
  • 单层递归逻辑:将当前节点的值cur->val添加到对应深度的向量中;递归地对左子节点和右子节点调用order函数,深度参数depth加一
//如果result向量的大小等于当前deth,意味着我们第一次访问这个深度的结点。则在result中添加一个新的空向量,为这个深度的结点做准备
if (result.size() == depth) result.push_back(vector<int>());
result[depth].push_back(cur->val);	//放入当前结点
order(cur->left, result, depth + 1);//往左遍历
order(cur->right, result, depth + 1);//往右遍历

CPP代码

#迭代法
class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> que;if (root != NULL) que.push(root);vector<vector<int>> result;while (!que.empty()) {int size = que.size();vector<int> vec;// 这里一定要使用固定大小size,不要使用que.size(),因为que.size是不断变化的for (int i = 0; i < size; i++) {TreeNode* node = que.front();que.pop();vec.push_back(node->val);if (node->left) que.push(node->left);if (node->right) que.push(node->right);}result.push_back(vec);}return result;}
};#递归法
class Solution {
public:void order(TreeNode* cur, vector<vector<int>>& result, int depth){if (cur == nullptr) return;if (result.size() == depth) result.push_back(vector<int>());result[depth].push_back(cur->val);order(cur->left, result, depth + 1);order(cur->right, result, depth + 1);}vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> result;int depth = 0;order(root, result, depth);return result;}
};

拓展题

  • 102.二叉树的层序遍历
  • 107.二叉树的层次遍历II
  • 199.二叉树的右视图
  • 637.二叉树的层平均值
  • 429.N叉树的层序遍历
  • 515.在每个树行中找最大值(opens new window)
  • 116.填充每个节点的下一个右侧节点指针
  • 117.填充每个节点的下一个右侧节点指针II
  • 104.二叉树的最大深度
  • 111.二叉树的最小深度

226.翻转二叉树

力扣题目链接

文章讲解:226.翻转二叉树

视频讲解:听说一位巨佬面Google被拒了,因为没写出翻转二叉树 | LeetCode:226.翻转二叉树

状态:对于二叉树的题,往往会涉及到遍历顺序,此题要求反转二叉树,也就每个结点的左右孩子进行反转,最直观的应该当属前序遍历或者后序遍历。

思路

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

返回值本来是不需要的,但是题目中要求给出返回root结点的指针,我们就直接使用题目定义好的函数。

TreeNode* invertTree(TreeNode* root)
  • 确定终止条件

当前结点为空就返回即可

if (root == NULL) return root;
  • 确定单层递归的逻辑

前序遍历,先交换左右孩子结点,然后反转左子树和右子树。

swap(root->left, root->right);
invertTree(root->left);
invertTree(root->left);

CPP代码

# 直接使用题目定义好的函数
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;}
};# 再开一个递归函数
class Solution {
public:void reverse(TreeNode* cur){if (cur == NULL) return;swap(cur->left, cur->right);reverse(cur->left);reverse(cur->right);}	TreeNode* invertTree(TreeNode* root) {reverse(root) return root;}
};

101. 对称二叉树

力扣题目链接

文章讲解:101. 对称二叉树

视频讲解:同时操作两个二叉树 | LeetCode:101. 对称二叉树

状态:只能说大致思路蒙对了,从根结点的左右子树去遍历。但是具体细节压根都想不明白。还是没搞清楚二叉树遍历的本质。

二叉树类的题目,确定遍历深度是非常重要的,决定了我们对题目理解的深度。

这道题目只能使用后序,即左右中,因为我们要不断收集左右孩子的信息,返回给上一个结点,如此循环,我们才能知道以左结点为根结点的树和以右结点为根结点的树是否是相互翻转的。因为只有后序遍历,我们才能把底部孩子是否相等的信息返回给上一层

使用的遍历方式,左子树左右中,右子树右左中,所以我把这个遍历顺序也称之为“后序遍历”(尽管不是严格的后序遍历)

这样遍历主要是因为,左子树的左侧对应右子树的右侧,左子树的右侧对应右子树的左侧

直接上伪代码!

伪代码

  • 确定参数和返回值:因为我们要比较的是根节点的两个子树是否是相互翻转的,进而判断这个树是不是对称树,所以要比较的是两个树,参数自然也是左子树节点和右子树节点。

返回值自然是bool类型。

bool compare(TreeNode* left, TreeNode* right){}
  • 确定终止条件:只关注不满足条件的情况

左空,右不空;右空,左不空;左右都空,对称;左右都不空,但是结点数值不相等;

if (left == NULL && right != NULL) return false;
else if (left != NULL && right == NULL) return false;
else if (left == NULL && right == NULL) return true;
else if (left->val != right->val) return false; // 注意这里我没有使用else
  • 确定单层递归逻辑:
  1. 比较二叉树的外侧是否对称:传入的是左结点的左孩子,右结点的右孩子
  2. 比较内侧是否对称:传入左结点的右孩子,右结点的左孩子
  3. 如果左右都对称就返回true,有一侧不对称就返回false
bool outside = compare(left->left, right->right);   // 左子树:左、 右子树:右
bool inside = compare(left->right, right->left);    // 左子树:右、 右子树:左
bool isSame = outside && inside;                    // 左子树:中、 右子树:中(逻辑处理)
return isSame;

CPP代码

class Solution {
public:bool compare(TreeNode* left, TreeNode* right) {// 首先排除空节点的情况if (left == NULL && right != NULL) return false;else if (left != NULL && right == NULL) return false;else if (left == NULL && right == NULL) return true;// 排除了空节点,再排除数值不相同的情况else if (left->val != right->val) return false;// 此时就是:左右节点都不为空,且数值相同的情况// 此时才做递归,做下一层的判断bool outside = compare(left->left, right->right);   // 左子树:左、 右子树:右bool inside = compare(left->right, right->left);    // 左子树:右、 右子树:左bool isSame = outside && inside;                    // 左子树:中、 右子树:中 (逻辑处理)return isSame;}bool isSymmetric(TreeNode* root) {if (root == NULL) return true;return compare(root->left, root->right);}
};

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

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

相关文章

微信公众号如何开通留言功能?

首先&#xff0c;我们需要了解为什么现在注册的公众号没有留言功能。这是因为所有在2018年之后注册的微信公众号都无法再自带留言功能。这一变化是根据微信的通知而实施的。自2018年2月12日起&#xff0c;微信对新注册的公众号进行了调整&#xff0c;取消了留言功能。这一决策主…

MySQL - 基础二

6、表的增删改查 CRUD : Create(创建), Retrieve(读取)&#xff0c;Update(更新)&#xff0c;Delete&#xff08;删除&#xff09; 6.1、Create 语法&#xff1a; INSERT [INTO] table_name[(column [, column] ...)]VALUES (value_list) [, (value_list)] ...value_list: v…

static关键字总结

static关键字的使用1. static: 静态的2. static 用来修饰的结构&#xff1a;属性、方法; 代码块、内部类&#xff1b;3. static修饰属性3.1 复习&#xff1a;变量的分类方式1&#xff1a;按照数据类型&#xff1a;基本数据类型、引用数据类型方式2&#xff1a;按照类中声明的位…

第十四届省赛大学B组(C/C++)子串简写

原题链接&#xff1a;子串简写 程序猿圈子里正在流行一种很新的简写方法&#xff1a; 对于一个字符串&#xff0c;只保留首尾字符&#xff0c;将首尾字符之间的所有字符用这部分的长度代替。 例如 internationalization 简写成 i18n&#xff0c;Kubernetes 简写成 K8s&#…

Java基础知识总结(37)

JUC容器 JUC基于非阻塞算法&#xff08;Lock Free 无锁编程&#xff09;提供了一组高并发的List、Set、Queue、Map容器。 JUC高并发容器是基于非阻塞算法实现的容器类&#xff0c;无锁编程算法主要通过CAS&#xff08;Compare And Swap&#xff09;volatile的组合实现&#x…

【SaaS,PaaS? XaaS -微参考】

介绍 以下是关于各种云服务模式的简要介绍&#xff0c;包括全称、定义、典型场景和应用&#xff1a; 缩写全称定义关键词典型场景和应用SaaSSoftware as a Service将软件以服务的形式交付给用户&#xff0c;用户通过互联网访问软件。提供软件电子邮件、在线办公套件&#xff…

JavaAPI操作HBase-Day2

Java代码操作HBase pom依赖,依赖版本要和软件一致 <dependencies><dependency><groupId>org.apache.hbase</groupId><artifactId>hbase-client</artifactId><version>2.5.5</version></dependency><dependency>…

android 14 apexd分析(1)apexd bootstrap

Apex的由来&#xff0c;我们都知道普通的apk我们可以通过应用商店playstore等进行更新&#xff0c;apex的引入是google希望也能通过playstore更新bin文件.so etc配置文件等类型文件. 这些文件的安装实际通过apexd来进行&#xff0c;现在我们来解析一下apexd&#xff0c; apexd的…

JAVAEE——文件IO之文件操作

文章目录 文件的创建和销毁File概述构造方法常用的方法getAbsolutePath()exists()isDirectory()isFile()createNewFile()delete()deleteOnExit()list()listFiles()mkdir() 文件的创建和销毁 上面我们介绍了文件的读写操作那么文件的创建等的操作如何进行呢&#xff1f;这个操作…

.NET 设计模式—简单工厂(Simple Factory Pattern)

简介 简单工厂模式&#xff08;Simple Factory Pattern&#xff09;属于类的创建型模式&#xff0c;又叫静态工厂方法模式&#xff08;Static FactoryMethod Pattern&#xff09;,是通过一个工厂类来创建对象&#xff0c;根据不同的参数或条件返回相应的对象实例。这种模式隐藏…

前视声呐目标识别定位(四)-代码解析之启动识别模块

前视声呐目标识别定位&#xff08;一&#xff09;-基础知识 前视声呐目标识别定位&#xff08;二&#xff09;-目标识别定位模块 前视声呐目标识别定位&#xff08;三&#xff09;-部署至机器人 前视声呐目标识别定位&#xff08;四&#xff09;-代码解析之启动识别模块 …

C语言之分支语句和循环语句

前言 一、什么是语句&#xff1f; 二、分支语句&#xff08;选择结构&#xff09; 2.1 if语句 2.2 switch语句 三、循环语句 3.1 while循环 3.2 break与continue语句 3.3 getchar()与putchar() 3.3.1 缓冲区 3.4 for循环 3.4.1 一些for循环的变种 3.5 do...while循…

AcWing 785. 快速排序——算法基础课题解

AcWing 785. 快速排序 文章目录 题目描述CGo模板 题目描述 给定你一个长度为 n 的整数数列。 请你使用快速排序对这个数列按照从小到大进行排序。 并将排好序的数列按顺序输出。 输入格式 输入共两行&#xff0c;第一行包含整数 n。 第二行包含 n 个整数&#xff08;所有…

C语言中的结构体:高级特性与扩展应用

前言 结构体在C语言中的应用不仅限于基本的定义和使用&#xff0c;还包含一些高级特性和扩展应用&#xff0c;这些特性和应用使得结构体在编程中发挥着更加重要的作用。 一、位字段&#xff08;Bit-fields&#xff09; 在结构体中&#xff0c;我们可以使用位字段来定义成员…

AJAX —— 学习(二)

目录 一、利用 JSON 字符串 返回数据 &#xff08;一&#xff09;基础代码 &#xff08;二&#xff09;原理及实现 二、nodmon 工具 自动重启服务 &#xff08;一&#xff09;用途 &#xff08;二&#xff09;下载 &#xff08;三&#xff09;使用 三、IE 缓存问题 &a…

QA测试开发工程师面试题满分问答8: mysql数据库的索引定义、用途和使用场景

MySQL数据库索引是一种数据结构&#xff0c;用于提高数据库的查询效率。索引是基于表中的一个或多个列构建的&#xff0c;它们允许数据库系统快速定位和访问表中的特定数据&#xff0c;而无需扫描整个表。 索引的定义 在MySQL中&#xff0c;可以使用CREATE INDEX语句定义索引…

pulsar集群部署流程及方案

# 部署方案: 集群模式部署,broker和bookie混合部署,zk同时部署在三台机器上面(资源充足zk最好单独部署,注意pulsar和zk版本兼容性) # 1.集群资源使用(实际测试情况CPU使用率比内存高,建议CPU设置大于内存,不同业务场景有差异) 三台主机centos7 16核16GB,每台挂载1TB机械硬盘(不…

Linux:进程终止和等待

一、进程终止 main函数的返回值也叫做进程的退出码&#xff0c;一般0表示成功&#xff0c;非零表示失败。我们也可以用不同的数字来表示不同失败的原因。 echo $?//打印最近一次进程执行的退出码 而作为程序猿&#xff0c;我们更需要知道的是错误码所代表的错误信息&#x…

MongoDB聚合运算符:$lte

文章目录 语法举例 $lte聚合运算符用于比较两个值&#xff0c;如果第一个小于等于第二个&#xff0c;返回true&#xff1b;如果第一个值大于第二个值&#xff0c;返回false。 语法 { $lte: [ <expression1>, <expression2> ] }$lte可以用来比较任何类型的值&…

嵌入式算法开发系列之卡尔曼滤波算法

卡尔曼滤波算法 文章目录 卡尔曼滤波算法前言一、卡尔曼滤波算法原理二、算法应用三、C语言实现总结 前言 在嵌入式系统中&#xff0c;传感器数据通常受到噪声、误差和不确定性的影响&#xff0c;因此需要一种有效的方法来估计系统的状态。卡尔曼滤波算法是一种基于概率理论的…