Day18 226翻转二叉树 101对称二叉树 100相同的树 572另一棵树的子树

226 翻转二叉树

递归前序遍历和后序遍历:

class Solution {
public:void swap(TreeNode*&a,TreeNode*&b){TreeNode*tmp = a;a = b;b = tmp;}void reverseTree(TreeNode* cur){if(cur==nullptr) return;swap(cur->left,cur->right);reverseTree(cur->left);reverseTree(cur->right);//后序遍历把这里顺序调换一下就行}TreeNode* invertTree(TreeNode* root) {reverseTree(root);return root;}
};

        递归中序遍历,这里需要有点区别了,如果按照正常的中序,那有些孩子可能在左边翻转完,到右面又翻转了一次,类似于今年一年级擦黑板,明年二年级擦黑板的情况。所以要做修改:

class Solution {
public:TreeNode* invertTree(TreeNode* root) {if (root == NULL) return root;invertTree(root->left);         // 左swap(root->left, root->right);  // 中invertTree(root->left);         // 注意 这里依然要遍历左孩子,因为中间节点已经翻转了return root;}
};

         另外本题还可以进行迭代法,其实也类似,迭代中序的话可能要有点变化:

//迭代前序
class Solution {
public:TreeNode* invertTree(TreeNode* root) {if(root == nullptr) return root;stack<TreeNode*> st;st.push(root);while(!st.empty()){TreeNode*cur=st.top();st.pop();swap(cur->left, cur->right);if(cur->right) st.push(cur->right);if(cur->left) st.push(cur->left);}return root;}
};
//迭代中序
class Solution {
public:TreeNode* invertTree(TreeNode* root) {stack<TreeNode*> st;TreeNode* cur = root;while (cur != NULL || !st.empty()) {if (cur != NULL) { // 指针来访问节点,访问到最底层st.push(cur); // 将访问的节点放进栈cur = cur->left;                // 左} else {cur = st.top(); st.pop();swap(cur->left,cur->right);   // 中cur = cur->left;               // 右}}return root;}
};

        但是如果用统一迭代法就不会存在这个问题了,因为是用栈来遍历而不是指针来遍历。

class Solution {
public:TreeNode* invertTree(TreeNode* root) {stack<TreeNode*> st;if(root != nullptr)st.push(root);while(!st.empty()){TreeNode*node = st.top();if(node){st.pop();if(node->right) st.push(node->right);st.push(node);st.push(nullptr);if(node->left) st.push(node->left);}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 != nullptr) que.push(root);while(!que.empty()){int size = que.size();while(size--){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;}
};

        总而言之,这道题比较简单,可以尝试多种遍历方式举一反三,注意中序的重复问题。

101 对称二叉树

给定一个二叉树,检查它是否是镜像对称的。

        首先由于上一题的影响,我想到的是将这个二叉树翻转,之后对比翻转前后是否相等,来判断这个二叉树是不是对称二叉树,但是出现了一些问题,总会有些特殊的情况最后两组的数据是相同的但是并不是对称二叉树,不管怎么遍历都是差一点,错误代码附上吧:

class Solution {
public:
void reverseTree(TreeNode* &cur) //翻转二叉树{if(cur==nullptr) return;swap(cur->left,cur->right);reverseTree(cur->left);reverseTree(cur->right);}void traversal(TreeNode* cur, vector<int>& vec) //遍历二叉树{if (cur == NULL) return;traversal(cur->left, vec);  // 左vec.push_back(cur->val);traversal(cur->right, vec); // 右}bool isSymmetric(TreeNode* root) {vector<int> v1;traversal(root, v1);vector<int> v2;reverseTree(root);traversal(root, v2);for(int i = 0; i < v1.size(); i++){if(v1[i] != v2[i]) return false;}return true;}
};

        此时,我想到了不如用层序遍历,为了避免出现上面方法的错误情况,即使是空的地方我也要给创造一个结点顶上去,但是不能创造太多,否则内存会爆,于是定义的结点为INT_MIN,在下一层创建节点是,如果没有左右孩子并且val为INT_MIN,则不会再创建,这样比较省内存,代码如下:

class Solution {
public:bool isSymmetric(TreeNode* root) {queue<TreeNode*> q;if(root) q.push(root);while(!q.empty()){int size = q.size();vector<int> vec;for(int i = 0; i<size; i++){TreeNode* node = q.front();q.pop();vec.push_back(node->val);if(node->left) q.push(node->left); else if(node->val != INT_MIN) q.push(new TreeNode(INT_MIN)); if(node->right) q.push(node->right);else if(node->val != INT_MIN) q.push(new TreeNode(INT_MIN));}vector<int> vec1;vec1.assign(vec.begin(), vec.end());reverse(vec.begin(), vec.end());if(vec != vec1) return false;}return true;}
};

        再后面就是代码随想录的后序递归遍历方法了:比较的是根节点的两颗子树,所以在递归遍历的过程中,也是要同时遍历两棵树。为什么要后序,要遍历两颗子树而且要比较内侧和外侧结点,所以准确的来说是一个树的遍历顺序是左右中,一个树的遍历顺序是右左中。

        我们来列写递归三部曲

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

我们要比较的是根节点的两颗子树是否是相互翻转的,进而判断对称,所以参数为两棵子树,返回值为bool类型。

bool compare(TreeNode* left, TreeNode* right)

2.确定终止条件:

首先要把两个节点为空的情况列写出,左空右不空,左不空右空,都是不对称return false;如果左右都为空,说明对称,返回true;后面如果节点数值不同就返回false。

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

 3.确定单层递归的逻辑

比较内外侧是否对称,如果其中有一侧不对称,就返回false;

bool outside = compare(left->left, right->right);   // 左子树:左、 右子树:右
bool inside = compare(left->right, right->left);    // 左子树:右、 右子树:左
bool isSame = outside && inside;                    // 左子树:中、 右子树:中(逻辑处理)
return isSame;

最后整体代码如下:

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;//可以用这个代替下面的几行:else return compare(left->left, right->right) && compare(left->right, right->left);// 此时就是:左右节点都不为空,且数值相同的情况// 此时才做递归,做下一层的判断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);}
};

 本题我们也可以使用迭代法,每次将两侧树的对应元素放入到队列里,比较是否相等,出现不相等直接寄。当然,也可以用栈来实现,把队列换成栈即可。队列代码如下:

class Solution {
public:bool isSymmetric(TreeNode* root) {if (root == NULL) return true;queue<TreeNode*> que;que.push(root->left);   // 将左子树头结点加入队列que.push(root->right);  // 将右子树头结点加入队列while (!que.empty()) {  // 接下来就要判断这两个树是否相互翻转TreeNode* leftNode = que.front(); que.pop();TreeNode* rightNode = que.front(); que.pop();if (!leftNode && !rightNode) {  // 左节点为空、右节点为空,此时说明是对称的continue;}// 左右一个节点不为空,或者都不为空但数值不相同,返回falseif ((!leftNode || !rightNode || (leftNode->val != rightNode->val))) {return false;}que.push(leftNode->left);   // 加入左节点左孩子que.push(rightNode->right); // 加入右节点右孩子que.push(leftNode->right);  // 加入左节点右孩子que.push(rightNode->left);  // 加入右节点左孩子}return true;}
};

 100 相同的树

给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。

如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。

 和上面非常类似,把compare函数稍作修改即可,让后面的对比内外变成对比的一致即可。

class Solution {
public:bool isSameTree(TreeNode* left, TreeNode* right) {if(left==nullptr&&right!=nullptr) return false;else if(left!=nullptr&&right==nullptr) return false;else if(left==nullptr&&right==nullptr) return true;else if(left->val!=right->val) return false;bool comleft = isSameTree(left->left, right->left);bool comright = isSameTree(left->right, right->right);bool Issame = comleft && comright;return Issame;}
};

572 另一棵树的子树

 

给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。

二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。

         这道题可以利用上面的判断两棵树是否相同来简化,后面的issubtree中,参数题里已经给了,终止条件为root = nullptr,也就是说当前遍历的结点是空了,所以本层递归就结束了,因为一个空树肯定不包含任何子树,返回false,如果找到了相等的两棵树,那就返回true;同时单层递归逻辑为如果往左或者往右递归,出现一样的即可,不要求全部一样。

class Solution {
public:bool isSameTree(TreeNode* left, TreeNode* right) {if(left==nullptr&&right!=nullptr) return false;else if(left!=nullptr&&right==nullptr) return false;else if(left==nullptr&&right==nullptr) return true;else if(left->val!=right->val) return false;bool comleft = isSameTree(left->left, right->left);bool comright = isSameTree(left->right, right->right);bool Issame = comleft && comright;return Issame;}bool isSubtree(TreeNode* root, TreeNode* subRoot) {if(root==nullptr) return false;if(isSameTree(root,subRoot))return true;bool left = isSubtree(root->left, subRoot);bool right = isSubtree(root->right, subRoot);return (left||right);}
};

        今天练习的很多二叉树的递归,主要还是得熟练掌握三要素法列写递归代码。

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

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

相关文章

python删除列表中字符串_python - 删除字符串中的字符列表

如果您正在使用python2并且您的输入是字符串(不是unicodes)&#xff0c;那么绝对最好的方法是remove_chars_translate_bytes&#xff1a;>>> chars_to_remove [., !, ?]>>> subj A.B!C?>>> subj.translate(None, .join(chars_to_remove))ABC否则…

C语言的格式控制符问题

写C程序遇到这样一个问题&#xff0c;定义了double变量&#xff0c;printf输出却要%f。一直以为应该用%lf&#xff0c;事实上VC6.0用%lf会报错。原因还要在探究。 贴吧有人说&#xff1a;double变量&#xff0c;scanf时必须用%lf&#xff0c;printf时要用%f或者%lf&#xff08;…

php无法用mail函数发送邮件之原因

[导读]PHP 需要一个已安装且正在运行的邮件系统&#xff0c;以便使邮件函数mail()可用。所用的邮件系统程序通过在 php.ini 文件中进行设置。用如下代码发送邮件&#xff0c;可总是发送失败。 [php] view plaincopyprint? 01.<?php 02.$to "xxxxxxxxqq.com";…

Linux内核设计与实现 总结笔记(第五章)系统调用

系统调用 内核提供了用户进程和内核交互的接口&#xff0c;使得应用程序可以受限制的访问硬件设备。 提供这些接口主要是为了保证系统稳定可靠&#xff0c;避免应用程序恣意妄行。 一、内核通信 系统调用在用户空间进程和硬件设备之间添加中间才能。作用有三&#xff1a; 为用户…

爬虫软件python彻底卸载_Python爬虫实践:如何优雅地删除豆瓣小组的帖子

前言文章起源于自己的一个需求&#xff1a;想要删除掉自己的若干个小号在豆瓣小组上的发帖及回复记录。这是一件看似简单的事情&#xff0c;但是一遍一遍的重复操作实在让我感到非常绝望&#xff0c;特别是删除自己的回复时&#xff0c;有时候回复的帖子的回复有好几十页&#…

高斯卷积核如何生成 C语言实现

对于学图像专业的人来说&#xff0c;对图像进行高斯滤波应该不会陌生&#xff0c;本质上就是将图像与高斯核进行卷积。 但是高斯核是如何生成的呢。matlab中有函数能自动生成高斯卷积核&#xff1a; gsfspecial(gaussian,3,1) gs 0.0751 0.1238 0.0751 0.1238 0.…

连接MySQL数据库时常见故障问题的分析与解决

连接MySQL数据库时常见故障问题的分析与解决 初学的mysql网友好象经常会碰到mysql无法连接的错误。特开贴收集这样问题的现象和原因。 先自己扔块砖头出来。 归纳如下&#xff1a; 故障现象 : 无法连接 mysql 错误信息1 &#xff1a;ERROR 1045 (28000): Access deni…

如何判断两个平面相交_七年级下册相交线与平行线全章节复习

5.1 相交线(一)相交线两条直线相交&#xff0c;形成4个角。1、两条直线相交所成的四个角中&#xff0c;相邻的两个角叫做邻补角&#xff0c;特点是两个角共用一条边&#xff0c;另一条边互为反向延长线&#xff0c;性质是邻补角互补&#xff1b;相对的两个角叫做对顶角&#xf…

spring dao层注解_Spring– DAO和服务层

spring dao层注解欢迎来到Spring教程的第三部分。 在这一部分中&#xff0c;我们将继续编写Timesheet应用程序&#xff0c;这次我们将实现DAO层&#xff0c;业务服务并编写一些测试。 在上一部分中&#xff0c;我们定义了GenericDao接口&#xff0c;该接口告诉我们需要对实体执…

Word 2007 如何自动生成目录以及设置正文第一页?

首先&#xff0c;讲解如何生成目录。 第一步&#xff0c;设置目录的小结的题目。这个需要对一级标题&#xff0c;二级标题&#xff0c;三级标题进行设置&#xff0c;设置方法如下图所示&#xff1a; 可以点击右键&#xff0c;对标题的格式进行修改。 第二步&#xff0c;直接生成…

python 优先队列_python中使用优先队列

相信对于队列的概念大家都不会陌生&#xff0c;这种先入先出的数据结构应用很广泛&#xff0c;像一般的生产消费都会用到队列&#xff0c;关于Queue的用法介绍可以参考我之前的文章 python中的Queue与多进程&#xff08;multiprocessing&#xff09;还有栈&#xff0c;栈是一种…

JHipster入门,第2部分

所以你回来了&#xff01; 在本系列的最后一部分中 &#xff0c;我们采用了单片路线创建了一个JHipster应用程序。 这是红色药丸路线&#xff1b; 生活与您习惯的差不多。 但是也许您喜欢挑战。 也许您想超越红色药丸并尝试蓝色药丸。 在这种情况下&#xff0c;Blue Pill是微服…

由于html元素加载导致的问题

js中要求执行的事件是在完全加载完&#xff0c;但由于本地环境测试一直没发现出问题&#xff0c;在上线后由于网络延迟导致元素加载慢&#xff0c;而事件执行完&#xff0c;没达到预期目标。 这时就需要用到属性 readyState readyState 属性返回当前文档的状态&#xff08;载入…

Linux下MySQL数据库常用基本操作 一

1、显示数据库 show databases; 2、选择数据库 use 数据库名; 3、显示数据库中的表 show tables; 4、显示数据表的结构 describe 表名; 5、显示表中记录 SELECT * FROM 表名 6、建库 create databse 库名; 7、建表 create table 表名 (字段设定列表)&#xff1b;mysql> cr…

C语言读取txt文档中的数据

1.说明 txt文档中的数据格式&#xff1a;前后数据用空格隔开&#xff1b;数据来源&#xff1a;matlab读取彩图的R、G、B三层的像素值&#xff0c;分别存放在三个txt文档中&#xff0c;用C读取到一维数组。动态申请数组&#xff0c;还是需要预先知道数组的大小&#xff0c;比静态…

cpickle支持的python版本_Python序列化模块pickle和cPickle

Python的序列化是指把变量从内存中变为可以储存/传输的数据/文件的过程. 在Python中叫pickling&#xff0c;在其他语言中也被称之为serialization&#xff0c;marshalling&#xff0c;flattening等等&#xff0c;都是一个意思。序列化之后&#xff0c;就可以把序列化后的内容写…

Intellij IDEA 4种配置热部署的方法

Intellij IDEA 4种配置热部署的方法 热部署可以使的修改代码后&#xff0c;无须重启服务器&#xff0c;就可以加载更改的代码。 第1种&#xff1a;修改服务器配置&#xff0c;使得IDEA窗口失去焦点时&#xff0c;更新类和资源 菜单Run -> EditConfiguration , 然后配置指定服…

mysql启动报错:Another MySQL daemon already running with the same unix socket.

[rootlocalhost ~]#/etc/init.d/mysqld restart Stopping mysqld: [ OK ] Another MySQL daemon already running with the same unix socket. Starting mysqld: [FAILED] 原因多个Mys…

malloc申请一维动态数组的错误

正确写法&#xff1a;int *tmp ( int * )malloc( H*W*sizeof(int) ); float *tmp ( float * )malloc( H*W*sizeof(float) ); double *tmp ( double * )malloc( H*W*sizeof(double) ); 错误写法&#xff1a;double *tmp ( double * )malloc( H*W*sizeof(double * ) ); 错…

java检查注入sql框架_Java:检查器框架

java检查注入sql框架我在JavaOne 2012上 了解的有趣的工具之一是Checker Framework 。 Checker Framework的网页之一 指出 &#xff0c;Checker Framework“增强了Java的类型系统&#xff0c;使其更加强大和有用”&#xff0c;从而使软件开发人员“能够检测并防止Java程序中的错…