对称二叉树

力扣题目链接(opens new window)

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

思路

本题中,不能单纯去比较左右子节点的是否对称(都有值且不为空)

因为如果按上面那样做的话,到子节点后就肯定是不对称的(对于左半边而言),但整体上看可能还是对称的,仍然满足题意,由此就会出现错误

因此,我们需要比较的是当前左右节点下的外侧内侧的节点是否对称,如图所示:

上图中,显然整课二叉树是对称的

我们在判断的时候只需将左2节点与右2节点的子节点按内侧与外侧区分,再进行比较即可

代码

递归法

按照递归三步走来:

1、确定递归函数的参数和返回类型

2、确定递归的终止条件

3、处理下一层的递归逻辑

class Solution {
public:
//确定递归函数的参数和返回值
bool cmp(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 = cmp(left->left, right->right);//外侧
bool inside = cmp(left->right, right->left);//内侧
bool res = outside && inside;
return res;//记得返回最终结果
}
bool isSymmetric(TreeNode* root) {
//判断根节点是否为空
if(root == NULL) return 0;
return cmp(root->left, root->right);
}
};
迭代法

定义两个节点,同时放入 队列 中,然后同时取出判断是否相等,直到遍历结束

class Solution {
public:
bool isSymmetric(TreeNode* root) {
//创建队列
queue<TreeNode*> que;
//判断根节点是否为空,为空直接对称
if (root == NULL) return true;
//获取左右节点(相对于root来说的)
//加入队列
que.push(root->left);
que.push(root->right); //队列不为空则遍历
while(!que.empty()){
//取出队列中的两个节点
TreeNode* left = que.front();
que.pop();
TreeNode* right = que.front();
que.pop();
// //左节点为空,右节点有值//左节点有值,右节点为空//左右节点有值但不同
// if(left == NULL && right != NULL || left != NULL && right == NULL || left->val != right->val){
// return false;
// }else if(left == NULL && right == NULL){
// continue;
// }
//左右节点均为空
if(left == NULL && right == NULL){
continue;
} //队列中如果没有同时放入两个节点就直接代表不对称了,即有一个为空就可以下判断
//其实还是对应之前的三种情况,只是在队列中表现方式不同
if((right == NULL || left == NULL|| (left->val != right->val))){
return false;
}
//排除上面的情况后就剩下不为空且对称的情况 //继续加入当前左右节点的子节点,依旧遵循内外侧原则
//外侧
que.push(left->left);
que.push(right->right);
//内侧
que.push(left->right);
que.push(right->left);
}
//完成上述遍历没返回false就是对称的
return true;
}
};
注意点

1、因为已经使用了队列,每次我们都需要放入两个节点,如果某次发现取的时候只有一个,那直接就可以判定当前情况为不对称‘

相同的树

https://leetcode.cn/problems/same-tree/

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

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

示例 1:

输入:p = [1,2,3], q = [1,2,3]

输出:true

示例 2:

输入:p = [1,2], q = [1,null,2]

输出:false

示例 3:

输入:p = [1,2,1], q = [1,1,2]

输出:false

思路

与对称二叉树的解法类似

只不过这里递归函数中,我们输入的分别是两个树的root

在处理单层逻辑时,要遵循以下原则:

二叉树A的左侧节点与二叉树B的左侧节点比较;

二叉树A的右侧节点与二叉树B的右侧节点比较;

上述结果完全相同才能证明两树相同

代码

使用递归法的思路

class Solution {
public:
//确定递归函数参数与返回值
bool cmp(TreeNode* p, TreeNode* q){
//确定终止条件(当前遍历节点为空)
if(p == NULL && q == NULL) return true;
else if(p == NULL || q == NULL)return false;
else if(p->val != q->val)return false;
//处理单层逻辑
bool leftside = cmp(p->left, q->left);
bool rightside = cmp(p->right, q->right);
bool res = leftside && rightside;
return res;
}
bool isSameTree(TreeNode* p, TreeNode* q) {
return cmp(q,p);
}
};

另一颗子树

https://leetcode.cn/problems/subtree-of-another-tree/

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

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

示例 1:

输入:root = [3,4,5,1,2], subRoot = [4,1,2]

输出:true

示例 2:

输入:root = [3,4,5,1,2,null,null,null,null,0], subRoot = [4,1,2]

输出:false

提示:

root 树上的节点数量范围是 [1, 2000]

subRoot 树上的节点数量范围是 [1, 1000]

-104 <= root.val <= 104

-104 <= subRoot.val <= 104

思路

先读懂题目,题目要求我们在root中寻找一个与subRoot相等的子树,如果存在该子树返回true,否则返回false

那么会有以下几种情况:

1、root与subRoot直接就是相等的

  • 两者都为NULL
  • 两者满足相等条件

2、subRoot是root的左子树

3、subRoot是root的右子树

分别针对上述情况进行处理即可

两颗二叉树怎么才算相等?

两颗二叉树相等的定义是它们的结构相同对应节点的值也相同

具体来说,以下条件满足时,两颗二叉树才算相等:

  1. 两棵树的根节点的值相等。
  2. 递归比较两棵树的左子树和右子树是否相等。如果都相等,则这两棵树相等;如果至少有一棵子树不相等,则这两棵树不相等。

需要注意的是,如果一棵树的节点为空,而另一棵树对应节点不为空,则这两棵树不相等。

代码

主函数

一般来说,如果涉及递归操作,都应该先讲递归函数

但是这里有点特殊,我想先说一下主函数(不然会不清楚递归函数要达到的目的)

class Solution {
public:
//先得有一个用于判断相等数的函数
//确定递归函数参数与返回值
bool traversal(TreeNode* p, TreeNode* q){ } bool isSubtree(TreeNode* root, TreeNode* subRoot) {
//root不能为空
if(root == NULL) return false; //root与subRoot相同,true
// if(traversal(root, subRoot))return true;
if(root->val == subRoot->val && traversal(root, subRoot)) return true; //分别判断root的左边和右边有无与subRoot相同的,满足一边即可
// return isSameTree(root->left, subRoot) || isSameTree(root->right, subRoot);
return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
};

在主函数isSubtree中,我们要判断的root中是否存在subRoot

首先得确定root的根节点不为空

然后判断当前节点(根节点)的值是否与subRoot当前节点的值相等【两棵树的根节点的值相等

除此之外,还要判断root中是否存在与subRoot相等的子树【结构上相等】

判断结构的时候就需要使用递归函数遍历所有节点了,待会讲递归函数

如果在结构和数值上都相等,那么可以返回true

否则需要在再继续去root的左右子树中找与subRoot相等的子树

具体到操作上就是:递归调用主函数

是的,就是因为这个迷惑的操作,所以需要先说主函数逻辑。。。

在递归查找root左右子树时,只要有一边找到与subRoot相等的子树,主函数就可以返回true

递归函数

根据上述分析,整体代码中其实使用了两处递归

主函数递归负责在root中递归查找左右子树

而traversal则负责在主函数递归中,判断当前root的子树是否与subRoot相等

class Solution {
public:
//先得有一个用于判断相等数的函数
//确定递归函数参数与返回值
bool traversal(TreeNode* p, TreeNode* q){
//确定终止条件(当前遍历节点为空)
if(p == NULL && q == NULL) return true;//当前root子树和subRoot均为空的情况,相等
else if(p == NULL || q == NULL) return false;//当前root子树和subRoot一方为空的情况,不相等
else if(p->val != q->val) return false;//当前root子树和subRoot值不相等,不相等 //处理单层逻辑
//递归查找当前root子树的左子树
bool leftside = traversal(p->left, q->left);
//递归查找当前root子树的右子树
bool rightside = traversal(p->right, q->right);
//综合左右子树情况,均返回true则表示结构上相等,判定当前root子树和subRoot相等
bool res = leftside && rightside;
return res;
} bool isSubtree(TreeNode* root, TreeNode* subRoot) { }
};
完整代码
class Solution {
public:
//先得有一个用于判断相等数的函数
//确定递归函数参数与返回值
bool traversal(TreeNode* p, TreeNode* q){
//确定终止条件(当前遍历节点为空)
if(p == NULL && q == NULL) return true;//当前root子树和subRoot均为空的情况,相等
else if(p == NULL || q == NULL) return false;//当前root子树和subRoot一方为空的情况,不相等
else if(p->val != q->val) return false;//当前root子树和subRoot值不相等,不相等 //处理单层逻辑
//递归查找当前root子树的左子树
bool leftside = traversal(p->left, q->left);
//递归查找当前root子树的右子树
bool rightside = traversal(p->right, q->right);
//综合左右子树情况,均返回true则表示结构上相等,判定当前root子树和subRoot相等
bool res = leftside && rightside;
return res;
} bool isSubtree(TreeNode* root, TreeNode* subRoot) {
//root不能为空
if(root == NULL) return false; //root与subRoot相同,true
// if(traversal(root, subRoot))return true;
if(root->val == subRoot->val && traversal(root, subRoot)) return true; //分别判断root的左边和右边有无与subRoot相同的,满足一边即可
// return isSameTree(root->left, subRoot) || isSameTree(root->right, subRoot);
return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot);
}
};

树的子结构

https://leetcode.cn/problems/shu-de-zi-jie-gou-lcof/

输入两棵二叉树A和B,判断B是不是A的子结构。(约定空树不是任意一个树的子结构)

B是A的子结构, 即 A中有出现和B相同的结构和节点值。

例如:

给定的树 A:

 3
/ \

4 5

/

1 2

给定的树 B:

4

/

1

返回 true,因为 B 与 A 的一个子树拥有相同的结构和节点值。

示例 1:

输入:A = [1,2,3], B = [3,1]

输出:false

示例 2:

输入:A = [3,4,5,1,2], B = [4,1]

输出:true

限制:

0 <= 节点个数 <= 10000

思路

与上一题思路一致

代码

代码方面,递归函数的停止条件需要做一下变化

/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
private:
bool traversal(TreeNode* A, TreeNode* B){
//确定停止条件
if(B == NULL) return true;//当B遍历到了叶子节点,意味着B树是A树的子结构
//A、B同时为空表示没找到相同子结构,A先为空则表示B不可能为子结构,均返回false
if(A == NULL && B == NULL || A == NULL) return false;
if(A->val != B->val) return false;
// if(A == NULL || A->val != B->val) return false;//也可以这样判断 //确定单层处理逻辑
bool leftside = traversal(A->left, B->left);
bool rightside = traversal(A->right, B->right);
bool res = leftside && rightside;
return res;
}
public:
bool isSubStructure(TreeNode* A, TreeNode* B) {
if(A == NULL || B == NULL) return false;
if(A->val == B->val && traversal(A, B)) return true;//确保结构一致 return isSubStructure(A->left, B) || isSubStructure(A->right, B);
}
};

【LeetCode二叉树#04】判断对称二叉树、相同的树、另一棵子树、树的子结构(二叉树相等判断)的更多相关文章

  1. C语言实现二叉树-04版

    二叉树,通常应当是研究其他一些复杂的数据结构的基础.因此,通常我们应该精通它,而不是了解:当然,可能并不是每个人都认同这种观点,甚至有些人认为理解数据结构就行了!根本没有必要去研究如何实现,因为大多数 ...

  2. 【LeetCode】Symmetric Tree(对称二叉树)

    这道题是LeetCode里的第101道题.是我在学数据结构——二叉树的时候碰见的题. 题目如下: 给定一个二叉树,检查它是否是镜像对称的. 例如,二叉树 [1,2,2,3,4,4,3] 是对称的. 1 ...

  3. 判断对称二叉树 python代码

    对称二叉树的含义非常容易理解,左右子树关于根节点对称,具体来讲,对于一颗对称二叉树的每一颗子树,以穿过根节点的直线为对称轴,左边子树的左节点=右边子树的右节点,左边子树的右节点=左边子树的左节点.所以 ...

  4. Leetcode:面试题28. 对称的二叉树

    Leetcode:面试题28. 对称的二叉树 Leetcode:面试题28. 对称的二叉树 Talk is cheap . Show me the code . /** * Definition fo ...

  5. 剑指offer17:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

    1 题目描述 输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) 2 思路和方法 (1)先在A中找和B的根节点相同的结点 (2)找到之后遍历对应位置的其他结点, ...

  6. [Leetcode] Construct binary tree from preorder and inorder travesal 利用前序和中续遍历构造二叉树

    Given preorder and inorder traversal of a tree, construct the binary tree. Note:  You may assume tha ...

  7. 剑指offer-重建二叉树04

    题目描述 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结果中都不含重复的数字.例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7, ...

  8. 数据结构(3) 第三天 栈的应用:就近匹配/中缀表达式转后缀表达式 、树/二叉树的概念、二叉树的递归与非递归遍历(DLR LDR LRD)、递归求叶子节点数目/二叉树高度/二叉树拷贝和释放

    01 上节课回顾 受限的线性表 栈和队列的链式存储其实就是链表 但是不能任意操作 所以叫受限的线性表 02 栈的应用_就近匹配 案例1就近匹配: #include <stdio.h> in ...

  9. 数据结构(一)二叉树 & avl树 & 红黑树 & B-树 & B+树 & B*树 & R树

    参考文档: avl树:http://lib.csdn.net/article/datastructure/9204 avl树:http://blog.csdn.net/javazejian/artic ...

  10. 剑指offer-面试题26-树的子结构-二叉树

    /* 题目: 输入两棵二叉树A和B,判断B是不是A的子树. */ /* 思路: 1.注意浮点数大小的判断. 2.判断树A的某个节点是否和树B的根节点是否相同, 若相同,则判断以A该节点为根节点是否包含 ...

随机推荐

  1. [转帖]rsync参数详解

    最近经常需要传送文件,学习到rsync这个非常好用的工具.rsync的传输方不像是scp复制粘贴,而是是创建一个镜像,所以在传输效率上比scp命令要快很多,缺点就是对文件的属性如权限.用户.组.时间戳 ...

  2. antv-x6 使用及总结

    1 简介 AntV是一个数据可视化(https://so.csdn.net/so/search?q=数据可视化&spm=1001.2101.3001.7020 )的工具(https://ant ...

  3. 浅析大促备战过程中出现的fullGc,我们能做什么?

    作者:京东科技 白洋 前言: 背景: 为应对618.双11大促,消费金融侧会根据零售侧大促节奏进行整体系统备战.对核心流量入口承载的系统进行加固优化,排除系统风险,保证大促期间系统稳定. 由于大促期间 ...

  4. 【分享代码片段】terraform中,如何从刚刚创建的 deployment 中获得所有容器的名字和 ip

    作者:张富春(ahfuzhang),转载时请注明作者和引用链接,谢谢! cnblogs博客 zhihu Github 公众号:一本正经的瞎扯 不好意思,刚刚才开始用 terraform,或许是更好的办 ...

  5. Centos7把home目录下多余的空间转移到/根目录下

    通过df-h发现,根目录只有32G,而home目录可用的,居然有142G.我现在想分出70G给根目录 把你需要挂载的机器的逻辑卷记住(上面的图,左边是逻辑卷,右边是虚拟磁盘) /dev/mapper/ ...

  6. webservice 发布与使用

    WebService,即Web服务,能使得运行在不同机器上的不同应用无须借助,专门的第三方软件或硬件,就可相互交换数据或集成. 第一次选择WebService,是为了替代数据库远程连接.我们都知道当S ...

  7. windowsbat命令大全

    Bat文件的创建及其命令大全 一.bat文件的创建 新建txt文本文件 向文本文件中输入命令 保存并修改文本文件后缀为.bat 双击保存后的bat文件,运行 二.bat命令大全 echo 和 @ @ ...

  8. vim 从嫌弃到依赖(9)——命令模式进阶

    上一篇文章更新还是在51前,最近发生了很多事情了,全国各地的疫情又有蔓延的趋势,北京朝阳区都已经开始实施居家办公.各位小伙伴请注意安全,安全平安的度过这个疫情. 废话不多说了,接着上次的内容往下写. ...

  9. 年末将至,Java 开发者必须了解的 16 个Java 顶级开源项目!

    年末将至,值得你关注的16个Java 开源项目! 本文已经收录自笔者开源的 JavaGuide: https://github.com/Snailclimb/JavaGuide ([Java学习+面试 ...

  10. Python自动化办公--Pandas玩转Excel【一】

    相关文章: Python自动化办公--Pandas玩转Excel数据分析[二] Python自动化办公--Pandas玩转Excel数据分析[三]_汀.的博客-CSDN博客 python处理Excel ...