题目描述

 
 
 
 原题链接:222. 完全二叉树的节点个数
解题思路
1、普通二叉树节点个数求法
(1)迭代:层序遍历BFS
遍历一层获取一层结点
/**
 * Definition for a binary tree node.
 * 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) {}
 * };
 */
class Solution {
public:
    int countNodes(TreeNode* root) {
        if(!root)       return 0;
        int res = 0;
        queue<TreeNode*> que;
        que.push(root);
        while(!que.empty()) {
            int n = que.size();
            while(n--) {
                TreeNode* node = que.front();
                que.pop();
                res++;
                if(node->left)      que.push(node->left);
                if(node->right)     que.push(node->right);
            }
        }
        return res;
    }
};
时间复杂度 
    
     
      
       
        O
       
       
        (
       
       
        n
       
       
        )
       
      
      
       O(n)
      
     
    O(n)
 空间复杂度 
    
     
      
       
        O
       
       
        (
       
       
        n
       
       
        )
       
      
      
       O(n)
      
     
    O(n)
(2)递归:先序遍历DFS
/**
 * Definition for a binary tree node.
 * 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) {}
 * };
 */
class Solution {
public:
    int nums = 0;
    int countNodes(TreeNode* root) {
        if(!root)       return 0;
        nums++;                             // 中:每遍历一个非空结点,加一
        if(!root->left && !root->right)     return 1;    // 刚开始遍历时,树中若只有一个结点,则返回1
        countNodes(root->left);             // 左
        countNodes(root->right);            // 右
        return nums;    // 最后从栈一个弹出的函数,有nums的最终值
    }
};
时间复杂度 
    
     
      
       
        O
       
       
        (
       
       
        n
       
       
        )
       
      
      
       O(n)
      
     
    O(n)
 空间复杂度 
    
     
      
       
        O
       
       
        (
       
       
        l
       
       
        o
       
       
        g
       
       
        n
       
       
        )
       
      
      
       O(log n)
      
     
    O(logn) (不考虑系统栈)
(3)迭代:后序遍历(子问题分解)
/**
 * Definition for a binary tree node.
 * 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) {}
 * };
 */
class Solution {
public:
    int countNodes(TreeNode* root) {
        if(!root)       return 0;
        int leftcnt = countNodes(root->left);       // 左
        int rightcnt = countNodes(root->right);     // 右
        return leftcnt + rightcnt + 1;              // 中:将结果返回给上一层
    }
};
时间复杂度 
    
     
      
       
        O
       
       
        (
       
       
        n
       
       
        )
       
      
      
       O(n)
      
     
    O(n)
 空间复杂度 
    
     
      
       
        O
       
       
        (
       
       
        l
       
       
        o
       
       
        g
       
       
        n
       
       
        )
       
      
      
       O(log n)
      
     
    O(logn) (不考虑系统栈)
2、完全二叉树性质求节点个数

 满二叉树的特点:左子树左侧边的高度=右子树右侧边的高度,节点个数=
    
     
      
       
        
         2
        
        
         n
        
       
       
        −
       
       
        1
       
      
      
       2^n-1
      
     
    2n−1。
 完全二叉树的特点:除了最后一层外,其余层全部为满二叉树。
可以将这个问题分解成子问题,求根节点所拥有的左右子树节点个的结点个数,最后得到整棵树的总个数。而每遍历到一颗子树时,可以利用满二叉树的特点查看该子树是否为一颗满二叉树,若为满二叉树,直接根据节点个数公式返回即可,若为不满二叉树,则算上该节点(总结点个数加一),然后再向下递归计算其左右子树结点个数。
/**
 * Definition for a binary tree node.
 * 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) {}
 * };
 */
class Solution {
public:
    int level = 0;
    int countNodes(TreeNode* root) {
        if(!root)       return 0;        
        // 先求左子树左侧高度和右子树右侧高度
        TreeNode* leftnode = root->left;
        TreeNode* rightnode = root->right;
        int leftLevel = 0, rightLevel = 0;      // 2左移从0开始,1左移从1开始
        while(leftnode) {
            leftLevel++;
            leftnode = leftnode->left;            
        }
        while(rightnode) {
            rightLevel++;
            rightnode = rightnode->right;
        }
        // 若为满二叉树,左子树左侧高度应该等于右子树右侧高度
        if(leftLevel == rightLevel)      return (1 << leftLevel) - 1;       // 2<<0 = 2 , 2<<n = 2^(n+1),因此规定从0开始
        // 若不为满二叉树,则算此结点个数,并求再求左右子树的结点个数
        return countNodes(root->left) + countNodes(root->right) + 1;
    }
};
时间复杂度 
    
     
      
       
        O
       
       
        (
       
       
        l
       
       
        o
       
       
        
         g
        
        
         2
        
       
       
        n
       
       
        )
       
      
      
       O(log^2 n)
      
     
    O(log2n)
 空间复杂度 
    
     
      
       
        O
       
       
        (
       
       
        l
       
       
        o
       
       
        g
       
       
        n
       
       
        )
       
      
      
       O(log n)
      
     
    O(logn)
注: 0 < n ≤ 4 0<n≤4 0<n≤4时, O ( n ) ≥ O ( l o g 2 n ) O(n) ≥ O(log^2 n) O(n)≥O(log2n);当 n ≥ 5 n≥5 n≥5时, O ( n ) < O ( l o g 2 n ) O(n) < O(log^2 n) O(n)<O(log2n)
参考文章:222.完全二叉树的节点个数、如何计算完全二叉树的节点数



















