【每日一题】力扣222 完全二叉树的节点个数

文章目录

    • 题目
    • 解题思路
    • 代码(C++)
      • 递归
      • 二分查找
    • 总结


题目

题目链接:力扣222.完全二叉树的节点个数

给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。

完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h 个节点。

示例 1:

【每日一题】力扣222 完全二叉树的节点个数_第1张图片

输入:root = [1,2,3,4,5,6]
输出:6

示例 2:

输入:root = []
输出:0

示例 3:

输入:root = [1]
输出:1

提示:

  • 树中节点的数目范围是[0, 5 * 104]
  • 0 <= Node.val <= 5 * 104
  • 题目数据保证输入的树是完全二叉树

进阶:遍历树来统计节点是一种时间复杂度为 O(n) 的简单解决方案。你可以设计一个更快的算法吗?


解题思路

这题主要想讲的是完全二叉树的性质,因为有一届的蓝桥的一题就是因为我把完全二叉树当成了满二叉树,让我那题没过。完全二叉树和满二叉树不一样的是,完全二叉树最后一层可以不是满的。

递归(遍历)

遍历的方法是最简单的,这种方法我应该不用说了,递归也好,迭代也好都可以,我就给一个最简单的代码吧。

本来不打算写题解的方法,但好像就没有什么讲的了,还是讲一下题解方法吧。

二分+位运算

这种方法需要用完全二叉树的性质,一个完全二叉树的节点数的范围是 [2h, 2h+1 - 1] ,其中 h 是树的深度。所以可以从这个范围里用二分查找判断树的节点个数具体是多少,再用二进制数依次表示这个范围内的每个节点,用这个二进制数和二叉树的节点做对比,缩小范围。

本题用到的位运算有:

  • 与(&):把数字转换成二进制,每位数字做与运算,即同为 1 才为 1
  • 左移(<<):把符号左边数字转换为二进制,所有数字向左移动 n 位(右边数字),右边空出来的补 0 或者说左边的数字乘以 2n
  • 右移(>>):和左移相反,补 1

具体可以看代码,就是二分查找加位运算

代码(C++)

递归

class Solution {
public:
    int f;
    void dfs(TreeNode *root) {
        if (!root)
            return ;
        f ++;
        dfs(root->left);
        dfs(root->right);
    }
    int countNodes(TreeNode* root) {
        dfs(root);
        return f;
    }
};

二分查找

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == nullptr) {
            return 0;
        }
        int level = 0;
        TreeNode* node = root;
        while (node->left != nullptr) {
            level++;
            node = node->left;
        }
        int low = 1 << level, high = (1 << (level + 1)) - 1;
        while (low < high) {
            int mid = (high - low + 1) / 2 + low;
            if (exists(root, level, mid)) {
                low = mid;
            } else {
                high = mid - 1;
            }
        }
        return low;
    }

    bool exists(TreeNode* root, int level, int k) {
        int bits = 1 << (level - 1);
        TreeNode* node = root;
        while (node != nullptr && bits > 0) {
            if (!(bits & k)) {
                node = node->left;
            } else {
                node = node->right;
            }
            bits >>= 1;
        }
        return node != nullptr;
    }
};

总结

这题用递归写真的没话说了,明显题目不是想考这个。用二分和位运算写真的有难度,通常的思维都是用二分查找的,很少用到判断上的。位运算在做题上确实快一点,但位运算不适用于项目上,因为难以理解,不好维护。这题第二种方法还是有必要要掌握的。

你可能感兴趣的:(每日一题,leetcode,算法,每日一题,二分查找)