【数据结构】有妙手、本手、俗手?这7道二叉树题(3)

  • ➡️简单来说:在二叉树里所有节点的值都相等
  • 遍历或者递归每个节点进行比较,直到每个节点的值都相等即可

💯圣经秒杀大法:

  • 我们先找到停止继续递归的条件:
    • 1️⃣当遇到root等于NULL,停止——return true
    • 2️⃣当子树存在并且子树的值不等于子树的左右子树的值——return false

Mark一下:相等是拿不到结果,记住要去抓不相等。我们想一想相等是不是只能继续递归下去,所以我们要去找不相等。

  • 接着我们找左右子树的逻辑关系:

在这里插入图片描述

  • 我们知道当左右子树都判断完,返回结果为true时才满足单值二叉树
    • 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 的右子树相等
  • 而判断 t 是否为 s 的子树的三个条件是的关系,即:

    • 1️⃣ 当前两棵树相等
    • 2️⃣ 或者,t 是 s 的左子树;
    • 3️⃣ 或者,t 是 s 的右子树。

我们发现:判断 是否是相等的树 与 是否是子树 的代码简直是对称美啊~
请添加图片描述

🌠动图解析:👇🏻

请添加图片描述

代码实现💡:

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 ,返回它节点值的 前序 遍历。

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

题目要求的不是要把前序的值打印一下,而是把前序的结果放在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 二叉树遍历

🌍题目描述:编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历输出遍历结果。

  • 输入描述:
    输入包括1行字符串,长度不超过100
  • 输出描述:
    可能有多组测试数据,对于每组数据, 输出将输入字符串建立二叉树后中序遍历的序列,每个字符后面都有一个空格。 每个输出结果占一行。

在这里插入图片描述

🌠画图解析:👇🏻

在这里插入图片描述

💫关键思路:

img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

f543e.png)

🌠画图解析:👇🏻

在这里插入图片描述

💫关键思路:

[外链图片转存中…(img-XaBCVQKE-1714273754907)]
[外链图片转存中…(img-Bbs6mN5M-1714273754907)]
[外链图片转存中…(img-xtCniql0-1714273754907)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上大数据知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

需要这份系统化资料的朋友,可以戳这里获取

  • 29
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值