二叉树相关题目分享

二叉树题目分享

本篇博客内容为作者写过的二叉树相关题目的题解。

226. 翻转二叉树

1.题目

在这里插入图片描述

2.题解

本题要求我们翻转整个二叉树,其实意思就是交换每个根节点的左右孩子节点。

实现起来其实是比较简单的,关键就是我们要确认遍历顺序。

如果我们选择中序遍历(左->中->右)的话,我们先交换了左孩子节点的左右孩子节点,然后交换了根节点的左右孩子节点,此时,之前交换过的那个左孩子结点跑到右孩子节点去了,如果再交换右孩子节点的左右孩子节点那我们就会使得右孩子节点的左右孩子节点交换回去了,而此时根节点的左孩子节点一次交换都没有发生,所以中序遍历显然很难实现。

如果我们选择前序遍历(中->左->右)的话,我们先交换了根节点的左右孩子节点,然后交换左孩子的左右孩子节点,再交换右孩子的左右孩子节点,我们就可以实现翻转二叉树了。

下面是代码:

void Swap(struct TreeNode* root){//交换左右孩子节点
    struct TreeNode* cur=root->left;
    root->left=root->right;
    root->right=cur;
}


struct TreeNode* invertTree(struct TreeNode* root) {
    if(root==NULL)
        return NULL;
    Swap(root);//中
    invertTree(root->left);//左
    invertTree(root->right);//右
    return root;
}

101. 对称二叉树

1.题目

在这里插入图片描述

2.题解

本题要求我们判断给定的二叉树是否沿中心轴对称,那么我们其实可以用两个指针兵分两路,分别遍历左子树与右子树,然后根据遍历的位置判断数值是否相等,相等返回真,反之返回假。

下面是代码:

int Same(struct TreeNode* root1, struct TreeNode* root2){
    if (root1 == NULL && root2 == NULL)//如果两个指针同时指向NULL,返回真
        return 1;
    if (root1 == NULL || root2 == NULL)//两个指针不同时为NULL且有一个指针为NULL,返回假
        return 0;
    if (root1->val != root2->val)//此时的两个指针指向的节点数值不同,返回假
        return 0;
    return Same(root1->left, root2->right) && Same(root1->right, root2->left);//将左孩子节点的左子树与右孩子节点的右子树传入进行判断,将左孩子节点的右子树与右孩子节点的左子树传入进行判断,有假则为假
}

bool isSymmetric(struct TreeNode* root) {
    if (root == NULL)//如果本身为NULL,返回真
        return true;
    return Same(root->left, root->right);
}

104. 二叉树的最大深度

1.题目

在这里插入图片描述

2.题解

本题需要我们找出与距离根节点最远的叶子结点,计算出深度。

我们本题主要运用递归去实现,如果我们知道了左子树与右子树的深度,我们直接返回max(左子树深度,右子树深度)+1,而左子树的深度与右子树的深度有也可以通过这种方法去计算,所以我们的递归思路就确定了。

下面是代码:

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

虽然看起来挺简短的,但是真正自己去实现起来确实还是很难做到的。

111. 二叉树的最小深度

1.题目

在这里插入图片描述

2.题解

上一题让求最大深度,本题需要我们求最小深度。

其实两道题大致思路还是一样的。我们如果知道了左右子树的最小深度,我们只用返回最小深度+1,而左右子树深度我们还是需要继续去求左子树的左右子树最小深度和右子树的左右子树最小深度,由此可见,我们依然需要使用递归去实现。

本题我们递归中的返回条件相比于上一题也有增加。

下面是代码:

int minDepth(struct TreeNode* root) {
    if (root == NULL)
        return 0;
    else if (root->left == NULL && root->right == NULL)//如果左右孩子同时为空,那么证明此节点为叶子结点,返回1就行
        return 1;
    
    else if (root->left == NULL && root->right != NULL)//如果有一边不为空,那么证明还没有到叶子结点,需要我们求出不为空的那一边的最小深度并返回深度+1
        return 1 + minDepth(root->right);
    else if (root->left != NULL && root->right == NULL)
        return 1 + minDepth(root->left);
    
    else if (root->left != NULL && root->right != NULL)//如果两边同时都不为空,我们就返回左右两边最小深度+1
        return 1 + fmin(minDepth(root -> left),minDepth(root -> right));
    return 0;
}

222. 完全二叉树的节点个数

1.题目

在这里插入图片描述

2.题解

本题有多种解法,一种是直接将该完全二叉树直接当成普通的二叉树去遍历,另一种是判断该二叉树是否为满二叉树,利用公式去计算。

第一种方法比较好理解,运用了后序遍历,先遍历左孩子节点,然后遍历右孩子节点,最后返回左孩子节点加右孩子节点再加上此时的根节点(+1)。等完成所有的递归后就可以得到所有节点的数量。

下面是代码:

int countNodes(struct TreeNode* root) {
    if(root==NULL)
        return 0;
    int leftnum=countNodes(root->left);//左
    int rightnum=countNodes(root->right);//右
    int ans=leftnum+rightnum+1;//中
    return ans;
}

第二种方法理解起来其实有一点难度。

因为该题目要求为完全二叉树,那么如果我们从某个根节点开始记录向左遍历的深度并记录向右遍历的深度,如果两个深度相同则表示该二叉树为满二叉树,因为完全二叉树的定义为最下面一层的节点集中在靠左边的位置。如果一个满二叉树深度为height,那么节点数为2的height次方-1。

下面是代码:

int countNodes(struct TreeNode* root){
    if(root==NULL)
        return 0;
    int leftDepth = 0;
    int rightDepth = 0;
    struct TreeNode* rightNode = root->right;
    struct TreeNode* leftNode = root->left;
    //求出左子树深度
    while(leftNode) {
        leftNode = leftNode->left;
        leftDepth++;
    }

    //求出右子树深度
    while(rightNode) {
        rightNode = rightNode->right;
        rightDepth++;
    }
    //若左右子树深度相同,为满二叉树。结点个数为2^height-1
    if(rightDepth == leftDepth) {
        return (2 << leftDepth) - 1;
    }
    //否则返回左右子树的结点个数+1
    return countNodes(root->right) + countNodes(root->left) + 1;
}

其中(2<<leftDepth)为2的height次方。

同时记录出左子树深度和右子树深度,如果深度相同则表示为满二叉树,用公式可以求出节点数并返回,如果不同就向下遍历一层并且在归的时候还要加上此根节点(+1)。

总结

二叉树的题目大部分都是要用递归去实现,要实现递归就需要我们找终止条件,找返回值,明白本级递归应该做什么。递归看起来容易,但是我们自己实现起来还是有些许难度的,要多加练习才能更熟练地使用递归去解决问题。

已经到底啦!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值