完全二叉树的节点个数

原题在这里

  概述题意,要求比O(n)复杂度更好的求出完全二叉树的节点数量的算法。

复制代码
struct TreeNode
{
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};
节点定义
复制代码

 

analyse:

  1.利用完全二叉树的性质,分类讨论:

复制代码
class Solution
{
    int dfs(TreeNode *n)
    {
        int ans = 0;
        while (n != nullptr)
        {
            n = n->left;
            ++ans;
        }
        return ans;
    }

public:
    int countNodes(TreeNode *root)
    {
        /*
        analyse:
            利用完全二叉树的性质,分类为4中情况
            令左右子树高度分别为lr,那么有:
                当l==r时候,左子树一定是满的,那么使用2^l-1求答案
                当l!=r时候,右子树一定不满,那么使用2^r-1求答案
        */
        if (!root)
            return 0;
        int l = dfs(root->left);  //左子树深度
        int r = dfs(root->right); //右子树深度
        if (l == r)
            return (1 << l) + countNodes(root->right); //如果相同,则往右取
        return (1 << r) + countNodes(root->left);      //否则往左取
    }
};
View Code
复制代码

  2.如上的另一种写法:

复制代码
class Solution
{
    int leftDepth(TreeNode *root)
    {
        return root ? 1 + leftDepth(root->left) : -1;
    }

public:
    int countNodes(TreeNode *root)
    {
        /*
        analyse:
            利用完全二叉树的性质,分类为4中情况
            令左右子树高度分别为lr,那么有:
                当l==r时候,左子树一定是满的,那么使用2^l-1求答案
                当l!=r时候,右子树一定不满,那么使用2^r-1求答案
            另一种写法。
        */
        if (!root)
            return 0;

        int d = leftDepth(root), res = 0;
        while (root)
        {
            // cout << "访问节点:" << root->val << endl;
            int rd = leftDepth(root->right);
            //右子树深度r与当前深度n的关系只有 n=r+1 or n = r
            if (d == rd + 1)
            {
                //右子树深度小,右走
                // cout << "  +=" << (1 << d) << endl;
                res += 1 << d;
                root = root->right;
            }
            else
            {
                //两子树深度相同,左走
                // cout << "  +=" << (1 << (d - 1)) << endl;
                res += 1 << (d - 1);
                root = root->left;
            }
            --d; // crutial, reduce total depth for subtree
        }
        return res;
    }
};
View Code
复制代码

  3.另外一种思路是用二分搜索节点,因为二分搜索的细节原因(懂的都懂,不懂的也不多说),就不写了。

【Over】

posted @   Renhr  阅读(33)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!
点击右上角即可分享
微信分享提示