- 2️⃣左右子树的
逻辑关系
:要看题目的意思去判断➡️ 左右子树要返回什么样的逻辑关系(eg:||
、&&
、+
、-
等) - 3️⃣遍历方式:根据题目要求来适配对应的
遍历方式
光说不练 假本事,下面我们操刀试试看🔍
🌍第1️⃣题:单值二叉树【难度:简单】
🏷️力扣地址:🌈965. 单值二叉树
🌍题目描述: 如果二叉树每个节点都具有
相同的值
,那么该二叉树就是单值二叉树。
只有给定的树是单值二叉树时,才返回 true;否则返回 false。
💫关键思路:
- ➡️简单来说:在二叉树里所有节点的值都相等
遍历
或者递归
每个节点进行比较,直到每个节点的值都相等即可
💯圣经秒杀大法:
- 我们先找到停止继续递归的条件:
- 1️⃣当遇到
root等于NULL
,停止——return true
- 2️⃣当
子树存在
并且子树的值不等于
子树的左右子树的值——return false
- 1️⃣当遇到
Mark一下:相等是拿不到结果,记住要去抓不相等。我们想一想相等是不是只能继续递归下去,所以我们要去找不相等。
- 接着我们找左右子树的逻辑关系:
- 我们知道当
左右子树
都判断完,返回结果为true
时才满足单值二叉树
- 1️⃣所以我们便知道此题的逻辑关系为
&&
- 1️⃣所以我们便知道此题的逻辑关系为
- 这道题的逻辑是:每个节点进行比较,直到每个节点的值都相等,那么是不是先是
访问根再左右子树
——>前序遍历
- 2️⃣每次递归先判断root的值是不是相等,若相等才去访问左右子树,不相等直接return false,不用继续递归下去了,其他的遍历方式都不适合
👆综上:
root为NULL、值不相等
➕&&
➕前序遍历
- 本质是通过不断递归比较每个节点是否相同【等号有
传递性
】
💥特别注意:
- 遍历法:
慎用全局变量
,最好每次调用的时候都控制一下 - 树为空时,也满足单值的条件,
return true
- 若左子树有不相等的值,则会直接返回,不需要再访问右子树
🌠动图解析:👇🏻
代码实现💡:
1️⃣遍历法:
bool flag =true;
void PreOrderCompare(struct TreeNode\* root,int val)
{
if(root==NULL || flag == false)//如果遇到false就不用继续遍历了
return ;
if(root->val!=val)
{
flag=false;
return ;
}
PreOrderCompare(root->left,val);
PreOrderCompare(root->right,val);
}
bool isUnivalTree(struct TreeNode\* root){
if(root==NULL)
return true;
flag=true;//初始全局变量
PreOrderCompare(root,root->val);
return flag;
}
2️⃣递归法
bool isUnivalTree(struct TreeNode\* root)
{
if(root==NULL)
return true;
if(root->left &&root->left->val !=root->val)
return false;
if(root->right &&root->right->val !=root->val)
return false;
return isUnivalTree(root->left)
&& isUnivalTree(root->right);
}
🌍第2️⃣题:相同的树【难度:简单】
🏷️力扣地址:🌈100. 相同的树
🌍题目描述:给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。
如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的。
🏷️解题关键
- 要准确的找出
四种
停止递归的条件并及时的return 相应的true/false
💫关键思路:
- ➡️ 当走到
根节点为空/树本为空
,则可证明两棵树相同 - 若树的结构相同,则再对值进行比较
💯圣经秒杀:
- 1️⃣当
q和p都为空
、q空和p非空
、q非空和p空
、q和p的值不相等
四种跳出递归的情况 - 2️⃣分析得知,我们选择:
&&
和前序遍历
ps:动图中的两个访问圈再代码里是同时进行
的,而且两棵树节点都NULL的时候才共同返回一个true
代码实现💡:
bool isSameTree(struct TreeNode\* p, struct TreeNode\* q){
if(q==NULL && p==NULL)//判断树or根节点都为空
return true;
if(q==NULL || p==NULL)//判断p、q的结构是否相同
return false;
if(q->val != p->val)//结构相同后,才是进行值的比较
return false;
return isSameTree(p->left,q->left)&& isSameTree(p->right,q->right);
}
🌍第3️⃣题:对称二叉树【难度:简单】
🏷️力扣地址:🌈101. 对称二叉树
🌍题目描述:给你一个二叉树的根节点 root , 检查它是否轴对称。
💫关键思路:
- ➡️ 本题目可复用上题的思路
- 只需把树
拆开
看成左子树
、右子树
两棵树,再复用
相同树的代码即可
💥特别注意:
- 注意
对称
的问题- 左树的左子树是和右树的右子树相比较的
- 左树的右子树是和右树的左子树相比较的
代码实现💡:
bool issam(struct TreeNode\* q,struct TreeNode\* p)
{
if(p == NULL && q == NULL)
return true;
if(p == NULL || q == NULL)
return false;
if(q->val != p->val)
return false;
return issam(q->left,p->right) && issam(q->right,p->left);
}
bool isSymmetric(struct TreeNode\* root){
if(root==NULL)
return true;
return issam(root->left,root->right);
}
🛫难度提升
🌍第4️⃣题:另一棵树的子树【难度:中等】
🏷️力扣地址:🌈572. 另一棵树的子树
🌍题目描述:给你两棵二叉树 root 和 subRoot 。检验 root 中是否包含和 subRoot 具有相同结构和节点值的子树。如果存在,返回 true ;否则,返回 false 。
- 二叉树 tree 的一棵子树包括 tree 的某个节点和这个节点的所有后代节点。tree 也可以看做它自身的一棵子树。
💫关键思路:
- 原树中的
所有子树
找出来和SubRoot
进行比较
一下就可以了
💥特别注意::
-
判断 t 是否和树 s 的任意子树相等。那么就转化成🌈100. 相同的树
即可,这个题的做法就是在 s 的每个子节点上,判断该子节点是否和 t 相等
。 -
判断
两个树是否相等
的三个条件是与
的关系,即:- 1️⃣当前两个树的根节点
值相等
; - 2️⃣
并且
,s 的左子树和 t 的左子树相等; - 3️⃣
并且
,s 的右子树和 t 的右子树相等
- 1️⃣当前两个树的根节点
-
而判断
t 是否为 s 的子树
的三个条件是或
的关系,即:- 1️⃣ 当前两棵
树相等
; - 2️⃣
或者
,t 是 s 的左子树; - 3️⃣
或者
,t 是 s 的右子树。
- 1️⃣ 当前两棵
我们发现:判断 是否是相等的树 与 是否是子树 的代码简直是对称美啊~
🌠动图解析:👇🏻
代码实现💡:
bool isSameTree(struct TreeNode\* p, struct TreeNode\* q){
if(p == NULL && q == NULL)
return true;
if(p == NULL || q == NULL)
return false;
if(p->val != q->val)
return false;
return isSameTree(p->left,q->left)&& isSameTree(p->right,q->right);
}
bool isSubtree(struct TreeNode\* root, struct TreeNode\* subRoot){
if(root==NULL)
return false;
//遍历跟,和所有的子树都比较一遍
if(isSameTree(root,subRoot))
return true;
//但凡有一个相等就认为是我的子树
return isSubtree(root->left,subRoot)||isSubtree(root->right,subRoot);
}
🌍第5️⃣题:二叉树的前序遍历【难度:中等】
🏷️力扣地址:🌈144. 二叉树的前序遍历
同学们卡到这里心想:二叉树的前序不就那三步吗?好戏还在后头
🌍题目描述:给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
题目要求的不是要把前序的值打印一下,而是把前序的结果放在
malloc的数组
里
returnSize
是输出型参数,与root不同,要解引用,外面要拿取数据
💫关键思路:
- 先把
TreeSize函数
输出给returnSize,然后malloc一个数组a,下标为i - 定义 preorder 表示当前遍历到 root 节点的答案。按照定义,我们只要首先将
root 节点的值
、数组
、下标i
加入答案,然后递归调用 preorder(root->left,a,i) 来遍历 root 节点的左子树,最后递归调用 preorder(root->right,a,i) 来遍历 root 节点的右子树即可,递归终止的条件为碰到空节点。
❌意料之外报错:
💥特别注意:
- 当root递归左子树的时候,左子树的
i++
,不影响root的i
(因为i是局部变量
),所以左右子树的i都相同,放进数组里会放在同一个位置。- 也就说:
不是一个i在往后走
对此我们可以传i的地址
,解引用i
,使得只有一个i
走完全程。
代码实现💡:
int TreeSize(struct TreeNode\* root)
{
return root == NULL? 0 :TreeSize(root->left)+TreeSize(root->right)+1;
}
void preorder(struct TreeNode\* root,int \*a,int \*pi)
{
if(root==NULL)
return;
a[(\*pi)++]=root->val;
preorder(root->left,a,pi);
preorder(root->right,a,pi);
}
int\* preorderTraversal(struct TreeNode\* root, int\* returnSize){
\* returnSize =TreeSize(root);
int\* a = (int\*)malloc(\* returnSize \* sizeof(int));
int i=0;
preorder(root,a,&i);
return a;
}
🌍第6️⃣题:二叉树遍历 【难度:中等】
🏷️地址:🌈KY11 二叉树遍历
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新
er(root,a,&i);
return a;
}
### 🌍第6️⃣题:二叉树遍历 【难度:中等】
🏷️地址:🌈[KY11 二叉树遍历](https://bbs.csdn.net/topics/618545628)
>
[外链图片转存中...(img-vJ94ap7P-1714273788782)]
[外链图片转存中...(img-ZZioyoFO-1714273788782)]
[外链图片转存中...(img-60OyyD7o-1714273788783)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新**
**[需要这份系统化资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618545628)**