Leetcode---完全二叉树的节点个数

生活,是一种缓缓如夏日流水般的前进,我们不要焦急。

题目描述

给你一棵完全二叉树的根节点 root ,求出该树的节点个数。完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
题目链接:https://leetcode-cn.com/problems/count-complete-tree-nodes/

解题思路:

对于任意二叉树,我们都可以使用广度优先搜索或深度优先搜索来计算节点的个数,时间复杂度和空间复杂度都是 O(n)。节点个数等于左子树个数+右子树个数+根结点个数。我们就可以得出如下代码
动图演示如下:
Leetcode---完全二叉树的节点个数_第1张图片

方法一:深度优先搜索计算节点个数

时间复杂度:O(n)【不考虑递归调用栈】
空间复杂度:O(n)

class Solution 
{
public:
    int countNodes(TreeNode* root) 
    {
        if(root==nullptr)	//如果为空,返回0
        {
            return 0;
        }
        //左子树个数+右子树个数+根结点
        return countNodes(root->left)+countNodes(root->right)+1;
    }
};

得出上述方法后,我们想想还有没有更优的方法呢?题目给的条件我们是否有全部用到呢?
这里我们发现题目中的一个题眼,那就是这个二叉树不是普通的二叉树,而是完全二叉树。
那么完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
我们知道完全二叉树最后一层节点的个数范围是在1~2^(k-1)之间。那么我们就可以利用满二叉树与完全二叉树的性质来优化代码。
针对情况一:若发现它的子树部分是满二叉树,直接返回该子树的结点个数 。结点个数等于
2^(k-1)

针对情况二:分别递归左、右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
动画演示如下:

根据上面的情况,我们可以写出如下方法二的解法。

方法二:根据完全二叉树的性质简化遍历次数

时间复杂度:O(logn * logn) 【不考虑递归调用栈】
空间复杂度:O(logn)

class Solution 
{
public:
    
    int countNodes(TreeNode* root) 
    {
        if(root==nullptr)
        {
            return 0;
        }
        int leftdepth=0;	//存储最左子树深度
        int rightdepth=0;	//存储最右子树深度
        TreeNode*left=root->left;
        TreeNode*right=root->right;
        while(left!=nullptr)    //得到左子树的深度
        {
            ++leftdepth;
            left=left->left;
        }
        while(right!=nullptr)   //得到右子树的深度
        {
            ++rightdepth;
            right=right->right;
        }
        if(leftdepth==rightdepth)   //判断该子树部分是不是满二叉树,是就返回它的个数
        {
            return (2<<leftdepth)-1;
        }
        return countNodes(root->left)+countNodes(root->right)+1;
    }
};

总结

1、由于树比较复杂,每当我们使用时都要注意边界条件的检查,即检查空指针。
2、我们在遍历树的代码中一旦要高度警惕,在每一处需要访问地址的时候都要问自己这个地址有没有可能是nullptr,如果是nullptr我们应该怎么处理。

Leetcode---完全二叉树的节点个数_第2张图片
如有错误之处或有更优解,还请各位指出,谢谢大家!!!
END…

你可能感兴趣的:(二叉树,leetcode,算法,c++)