二叉树OJ

前言、

我们在做二叉树OJ题时,需要注意的点

1、大多数情况下需要用递归解决

2、递归函数的参数选择

3、选择哪种遍历方式递归

4、递归的结束条件是什么

5、递归的返回值

如果在遇到比较难的递归问题,我们一定要多画递归展开图,画图过程中能帮助我们更好的理解递归的返回流程。

树的节点:

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

一、二叉树的最大深度

题目介绍:

二叉树OJ_第1张图片

解题思路:我们采用前序遍历的方式进行递归运算,我们只需要找到左子树和右子树相对较跟节点更深的节点加一就可以。

题解代码:

int maxDepth(struct TreeNode *root) 
{
    if (root == NULL) return 0;
    return fmax(maxDepth(root->left), maxDepth(root->right)) + 1;
}

二、单值二叉树

题目介绍:

二叉树OJ_第2张图片

解题思路:我们采用后序遍历的方式进行递归运算,我们判断一个树是否是单值二叉树,只需要判断每个子树的左右节点的值和根节点的知否相同,如果不同返回false,否则继递归,直到整棵树都递归完。

bool isUnivalTree(struct TreeNode* root)
{
    if(root==NULL)
    {
        return true;
    }
    //判断左数
    if(root->left!=NULL)
    {
        if(root->left->val!=root->val)
        {
            return false;
        }
    }
    //判断右树
    if(root->right!=NULL)
    {
        if(root->right->val!=root->val)
        {
            return false;
        }
    }

    //递归每个节点
    return isUnivalTree(root->left)&&isUnivalTree(root->right);
}

三、二叉树的前序遍历

题目介绍:

二叉树OJ_第3张图片

解题思路:我们需要先知道前序遍历指先便利根节点,其次是左孩子结点和右孩子节点,对于这道题来说,我们需要创建一个数组,来存放根节点的值。数组的大小为这棵树节点的个数。这下我们就一一解决这个问题:

1、节点的个数:

二叉树OJ_第4张图片

2、根节点存放在数组中

二叉树OJ_第5张图片

3、先序递归整个数组

二叉树OJ_第6张图片注意:这里我们必须穿的是 i 的地址,因为形参只是形参的一个临时拷贝,每次递归都会传一个 i 而这其中每个函数的 i 互不影响,显然这不是我么不你想要的结果,我们想要的是这些递归函数公用一个 i 。所以我们需要传 i 的地址。

四、中序遍历和后序遍历

题目介绍:

二叉树OJ_第7张图片二叉树OJ_第8张图片

解题思路:之所以把这两道题放在一起是因为他们可以说是,和上面一道题是一毛一样。

只是我们只需要将根节点放入数组这个步骤的位置有所变化:

中序遍历:先左子树递归,在根节点放入数组,在右子树递归。

后序遍历:先左子树递归,在右子树递归,最后将根节点放入数组。

题解代码(二叉树的中序遍历):

int TreeSize(struct TreeNode* root)
{
    if(root==NULL)
    {
        return 0;
    }
    return TreeSize(root->left)+TreeSize(root->right)+1;
}
void InOrder(struct TreeNode* root,int*a,int*i)
{
    if(root==NULL)
    {
        return;
    }
    InOrder(root->left,a,i);
    a[*i]=root->val;
    (*i)++;
    InOrder(root->right,a,i);
}

int* inorderTraversal(struct TreeNode* root, int* returnSize)
{
    int size=TreeSize(root);
    int*a=(int*)malloc(sizeof(int)*size);
    *returnSize=size;
    int i=0;
    InOrder(root,a,&i);
    return a;
}

题解代码(二叉树的后序遍历):

int TreeSize(struct TreeNode* root)
{
    if(root==NULL)
    {
        return 0;
    }
    return TreeSize(root->left)+TreeSize(root->right)+1;
}
void PostOrder(struct TreeNode* root,int*a,int*i)
{
    if(root==NULL)
    {
        return;
    }
    PostOrder(root->left,a,i);
    PostOrder(root->right,a,i);
    a[*i]=root->val;
    (*i)++;
}
int* postorderTraversal(struct TreeNode* root, int* returnSize)
{
    int size=TreeSize(root);
    int*a=(int*)malloc(sizeof(int)*size);
    *returnSize=size;
    int i=0;
    PostOrder(root,a,&i);
    return a;
}

五、相同的树

题目介绍:

二叉树OJ_第9张图片

解题思路:我们只需要判断两棵树的每个节点都相同便可以知道他们是相同的树。

遍历顺序:先序遍历。

递归结束条件:root==NULL;

递归参数:q->left     p->left   和   q->right     p->right

题解代码:

bool isSameTree(struct TreeNode* p, struct TreeNode* q)
{
    //两个都为空
    if(p==NULL&&q==NULL)
    {
        return true;
    }
    //其中一个为空
    if(p==NULL||q==NULL)
    {
        return false;
    }

    //两个都不为空
    if(q->val!=p->val)
    {
        return false;
    }

    return isSameTree(q->left,p->left)&&isSameTree(q->right,p->right);
}

六、另一颗子树

题目介绍:

二叉树OJ_第10张图片

解题思路:

有了  ”相同的树 “ 题目的铺垫,这道题也就相对简单许多。  

我们只需要判断有没有一个子树是和 subRoot相等的。

遍历顺序:先序遍历。

递归结束条件:root==NULL;

递归参数:root->left     subRoot   和   root->right     subRoot

我们可以借用“相同的数”代码来实现

题解代码:

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(root->val==subRoot->val)
    {
        if(isSameTree(root,subRoot))
        {
            return true;
        }
    }
    return isSubtree(root->left,subRoot)
        ||isSubtree(root->right,subRoot);
}

七、翻转二叉树

题目介绍:

二叉树OJ_第11张图片

题解思路:

我们需要将二叉树的左右孩子都交换,交换的是树的节点,而不是数节点的值。我们在交换数的节点是需要用到二级指针。

遍历顺序:中序遍历。

递归结束条件:root==NULL;

递归参数:root->left   root->right 

题解代码:

void Swap(struct TreeNode**p1,struct TreeNode**p2)
{
    struct TreeNode*temp=*p1;
    *p1=*p2;
    *p2=temp;
}
struct TreeNode* invertTree(struct TreeNode* root)
{
    if(root==NULL)
    {
        return root;
    }
 
    //中序遍历
    Swap(&root->left,&root->right);
    invertTree(root->left);
    invertTree(root->right);

    return root;
}

八、对称二叉树

题目介绍:二叉树OJ_第12张图片

解题思路:我们判断一个二叉树是否对称,换个思路就是在判断这个二叉树的左子树翻转后和右子树是否相等。

遍历顺序:后序遍历。

递归结束条件:

if(left==NULL&&right==NULL)

    {

        return true;

    }

    if(left==NULL||right==NULL)

    {

        return false;

    }

    if(left->val!=right->val)

    {

        return false;

    }

递归参数:struct TreeNode*left      struct TreeNode*right 

我们需要判断 :           左子树的左孩子是否等于右子树右孩子

                                    左子树的右孩子是否等于右子树的左孩子

题解代码:

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

}


bool isSymmetric(struct TreeNode* root)
{
    if(root==NULL)
    {
        return true;
    }
    return symmetry(root->left,root->right);
}

总结、

二叉树的OJ题这篇博客就讲完了,这些题目都来自 力扣 。大家有什么不懂的问题尽管在评论区里题,我们一起讨论解决。最后还望大家动动小手点赞收藏评论支持支持,你们的支持是我最大的动力,我也会持续向大家输送好文。加油,共勉!!!

你可能感兴趣的:(算法,数据结构,c语言)