第20天(简单题 二分查找&递归)

打卡第二十天
3道简单题 (简单在哪里....二叉树咋这么难)
image


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


方法一: 递归:完全二叉树只有两种情况,一是满二叉树,二是最后一层叶子节点没有满。
对于情况一,用 2^树深度 - 1 来计算。
对于情况二,分别递归左子树和右子树,递归计算左子树节点数 + 右子树节点数 + 1。

代码:

class Solution {
public:
    int countNodes(TreeNode* root) {
        if (root == nullptr){
            return 0;
        }
        TreeNode* left = root->left;//左子树指针
        TreeNode* right = root->right;//右子树指针
        int leftDepth = 0, rightDepth = 0;//初始化左右子树深度为0
        while (left) {  // 求左子树深度
            left = left->left;
            leftDepth++;
        }
        while (right) { // 求右子树深度
            right = right->right;
            rightDepth++;
        }
        if (leftDepth == rightDepth) {
            return (2 << leftDepth) - 1; // (2<<1) 相当于2^2,所以leftDepth初始为0
        }
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};


方法二: 二分查找+位运算
完全二叉树的最后一层节点编号是连续的,在 [2^level, 2^(level+1)-1] 范围内二分查找最后一个存在的节点
节点编号 k 的二进制表示(去掉最高位的1)就是从根节点到该节点的路径: 0 表示向左,1 表示向右

位运算实现逻辑:
image


代码:

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;
        }
        
        // level层是最底层,节点编号从 2^level 到 2^(level+1)-1
        int low = 1 << level;                    // 最低可能节点编号:2^level
        int high = (1 << (level + 1)) - 1;       // 最高可能节点编号:2^(level+1)-1
        
        // 二分查找:在[low, high]范围内找到最后一个存在的节点编号
        while (low < high) {
            int mid = (high - low + 1) / 2 + low;  // 向上取整,避免死循环
            if (exists(root, level, mid)) {
                low = mid;        // mid存在,说明最终答案 >= mid
            } else {
                high = mid - 1;   // mid不存在,说明最终答案 < mid
            }
        }
        return low;  // 此时low == high,就是节点总数
    }

    // 判断编号为k的节点是否存在
    bool exists(TreeNode* root, int level, int k) {
        int bits = 1 << (level - 1);  // 用于位运算的掩码

        TreeNode* node = root;
        
        // 根据k的二进制表示从高位到低位遍历路径
        while (node != nullptr && bits > 0) {
            if (!(bits & k)) {     // 当前位为0,往左走
                node = node->left;
            } else {               // 当前位为1,往右走
                node = node->right;
            }
            bits >>= 1;           // 移到下一位
        }
        return node != nullptr;   // 如果node不为空,说明该节点存在
    }
};

int bits = 1 << (level - 1); // 用于位运算的掩码

image

耗时≈两小时 明天继续

posted @ 2025-11-10 00:42  Wy0518  阅读(6)  评论(0)    收藏  举报