链式二叉树高质量OJ—【Leedcode】

简介: 链式二叉树高质量OJ—【Leedcode】

1. 单值二叉树


题目


题目分析

我们在这里首先想到的还是用遍历的想法来实现,把整个数都遍历一遍,看看有没有和val不相等的值,我们这时也可以发现前序遍历比较实用(一来就访问他的根,再访问他的左右孩子)


代码实现分析:


1. 首先在主函数中首先使用if条件判断,判断树的根节点是不是空,是空,就返回true(没有违背单值二叉树的定义)


2. 调用前序遍历,实现前序遍历函数


3. 前序遍历函数中,也要判断父亲节点是不是空,是空就回退到调用左儿子的地方,开始递归调用右孩子,直到遍历完整颗树,都没找到,或者是找到不同的值,一层一层的返回上去.....


易错点1:我们在找到的时候,回退出递归的时候,由于我们回退到的是上一层的左节点,这时即使找到了不同的值,我们还要进行右子树递归,这时就显得非常多余,如何改进呢?


方法:我们发现在前序遍历函数中的if判断条件可以完善一下


易错点2:我们这里先写的是不带返回值的,我们定义了一个全局的flag,先将flag初始化为true,后面如果不是单值二叉树的话,我们又将flag改为false,但是我们提交的时候,会有测试用例跑步过去,其实就是这里定义全局flag的问题,这里假如前一棵树不是单值二叉树(flag=false),但是这时第二次调用单值二叉树的时候,本来输出的结果是true,但是这时却输出false,显然是有问题的,怎么解决呢?


方法:在主函数调用前序遍历函数的前面,每次将flag初始化为true


代码实现

不带返回值版本

bool flag=true;
void PreOrderCompare(struct TreeNode* root ,int val)
{
   if(root == NULL || flag ==false)//这里的判断条件flag==false就是(易错点1)说的
    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;//每次调用前序遍历,都要将flag初始化为true(易错点2)
      PreOrderCompare(root,root->val);
      return flag;
}


带返回值版本

这里可以采用数学的交换律

a=b 、b=c ——> a=c

每个节点和自己的左右孩子比较,左右孩子又和自己的左右孩子比较,一直遍历完。。。。

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. 相同的树

题目

题目分析

题目是比较两棵树是否相同,也就是看两棵树所有节点的数据是不是相同,这时其实还是采用同时遍历两颗树的方法进行比较,这时就有一下三种情况需要分别处理:


1. 当两颗树都是空的情况,返回true


2. 当两棵树一颗为空,另一颗不为空的时候,就直接返回false


3. 走到这里证明两棵树都不为空,这时比较数据,采用同时递归两棵树的方式进行比较,只有比较到不同的情况,返回false,否则就一直遍历,如果直到遍历完都没又不同的数据,那这两棵树就是相同的了


代码实现

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);
}

3. 对称二叉树

题目

题目分析

题目的意思是判断这颗二叉树是不是对称的,我们发现可以将这颗二叉树分成两个子树进行比较,分别递归比较左子树的left和右子树的right、左子树的right和右子树的letf,如果比较晚了,都一样,那就是对称二叉树


实现步骤:


1. 先判断根节点是不是NULL,是,就返回true


2. 根节点不为NULL,再判断左右孩子节点是不是同时为NULL,如果是,那就返回true


3. 走到这里,那就是左右孩子不同时为空,但是有一个为空,那就返回false


4. 走到这里,那就是左右孩子都不为NULL,那就开始比较节点中的数据,如果不相等,那就返回false


5. 走到这里,那就是左右孩子节点数据相等,就开始递归左孩子节点的left节点和右孩子的right节点、递归左孩子的right节点和右孩子的left节点,两个比较都返回true,这时这颗二叉树才是对称的,否则就不对称


代码实现

bool isSymmetricsSubTree(struct TreeNode* root1,struct TreeNode* root2)
  {
       if(root1 == NULL && root2 ==NULL)
       return true;
       if(root1 == NULL || root2 == NULL)
       return false;
       if(root1->val != root2->val)
        return false;
        return isSymmetricsSubTree(root1->left,root2->right)
            &&  isSymmetricsSubTree(root1->right,root2->left); 
  }
bool isSymmetric(struct TreeNode* root){
    if(root == NULL)
    return true;
    return isSymmetricsSubTree(root->left, root->right);
}

4. 另外一颗子树


题目

题目分析

题目的意思其实是判断主树中是否有和子树相同的二叉树,这里还是采用遍历的思路


实现步骤:


1. 先判断主树的根节点是不是NULL,是,那就直接返回false


2. 不是NULL,那就开始递归遍历,这是我们可以用这样的方法,把主树的每个节点都和子        树递归比较,也就是前面判断两棵树是不是相同的二叉树的方法(2.相同二叉树)


3. 如果同时遍历比较两棵树,isSameTree返回的是true,那证明两棵树完全一样,如果不一      样,我们这是开始递归isSubtree,把根节点换成左孩子节点和子树进行比较,不相同,那      就开始递归遍历比较右孩子节点和子树,直到将主树的所有节点都和子树进行比较了,          isSameTree都没有返回true,那就是主树里面没有和子树一样的子二叉树


代码实现

注意1:这里的isSubtree返回的是左孩子比较结果 || 右孩子比较结果,也就是左右孩子有一个和子树一样,就返回true


注意2 :这里的isSubtree的返回值,是靠isSameTree带回的


举例:假如遍历比较完了一个根节点的左孩子,这时返回的是false,然后开始遍历这个根节点的右孩子,这是返回的是true,false || true 这时返回的是true

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. 二叉树的前、中、后序遍历


5.1 二叉树的前序遍历

题目


题目分析

题目的意思是遍历这颗二叉树,并把前序遍历的结果放到一个数组里面返回,那这个数组需要是malloc出来的


代码实现步骤:


1. 先判断这颗二叉树的根节点是否为空,为空,直接就return


2. 如果不是NULL,那这时就创建一个子函数,用来返回这个二叉树有多少个节点,然后再动态开辟一个数组用来存数据


3. 再创建一个子函数,用来前序遍历这个二叉树,把数据存储到开辟的空间中,最后返回出去

代码实现

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;
}


注意点

上面的代码中,我们传数组a的下标,采用了传指针的方式,为什么呢?(局部变量的原因)


因为在像下面的举例中,我们可以发现,在递归调用存储完3的时候i=2,然后i++,这时的i就变成了3,但是这时遍历3的左右孩子节点的时候发现都为空,这时2的左节点遍历就结束了,就开始右递归,但是本来i为3,但是在返回后,由于i是局部变量,i的值在2递归右孩子节点的函数中是2,但是这时又要存储节点4里的数据,这时前面存储的3就会被2覆盖掉,然后i++,后面就会有一个空的元素,执行就是随机值


觉得文字太多,直接看下面的递归展开图!!!!


中序和后续遍历的OJ练习题就根据上面讲的前序遍历自己去做下哦!!!



相关文章
|
5月前
二叉树OJ题(1)
二叉树OJ题(1)
36 0
【LeetCode】——链式二叉树经典OJ题详解
在之前的文章讲解了二叉树的链式结构的实现以及前、中、后序的遍历。不知道大家看完后有没有理解和有所收获,今天基于那篇文章给大家分享讲解几道经典的题目,更便于大家的理解和深入。
|
5月前
|
存储 算法 IDE
数据结构与算法⑯(第四章_下)二叉树的层序遍历+判断完全二叉树+一道OJ
数据结构与算法⑯(第四章_下)二叉树的层序遍历+判断完全二叉树+一道OJ
46 1
|
存储 C++
【C++】二叉搜索树经典OJ题目
二叉搜索树的几道经典OJ面试题
|
5月前
二叉树基础OJ题
二叉树基础OJ题
34 1
|
5月前
|
存储
栈与队列相关OJ题
栈与队列相关OJ题
21 0
|
5月前
|
API
二叉树的OJ练习(二)
二叉树的OJ练习(二)
|
11月前
|
算法
代码随想录算法训练营第十四天 | LeetCode 102. 二叉树的层序遍历、LeetCode 226. 翻转二叉树、LeetCode 101. 对称二叉树
代码随想录算法训练营第十四天 | LeetCode 102. 二叉树的层序遍历、LeetCode 226. 翻转二叉树、LeetCode 101. 对称二叉树
55 0
|
11月前
|
存储 算法
代码随想录算法训练营第十三天 | LeetCode 144. 二叉树的前序遍历、LeetCode 145. 二叉树的后序遍历、LeetCode 94. 二叉树的中序遍历
代码随想录算法训练营第十三天 | LeetCode 144. 二叉树的前序遍历、LeetCode 145. 二叉树的后序遍历、LeetCode 94. 二叉树的中序遍历
58 0
|
存储
链式二叉树OJ题思路分享
链式二叉树这一个板块的考题还是比较多的,这里我给大家分享几道很经典的OJ题,仅供参考! 分别是 1. 单值二叉树力扣965题----- 2. 检查两棵树是否相同力扣100题 ----- 3. 对称二叉树 力扣101题