题目描述
Given a complete binary tree, count the number of nodes.
Note:
Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.
Example:
Input:
1
/
2 3
/ \ /
4 5 6
Output: 6
代码
递归,未利用完全二叉树特性
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
int countNodes(TreeNode* root) {
if(root==NULL) return 0;
return 1+countNodes(root->left)+countNodes(root->right);
}
};
思路二
首先需要明确完全二叉树的定义:它是一棵空树或者它的叶子节点只出在最后两层,若最后一层不满则叶子节点只在最左侧。
再来回顾一下满二叉的节点个数怎么计算,如果满二叉树的层数为h,则总节点数为:2^h - 1.
那么我们来对root节点的左右子树进行高度统计,分别记为left和right,有以下两种结果:
left == right。这说明,左子树一定是满二叉树,因为节点已经填充到右子树了,左子树必定已经填满了。所以左子树的节点总数我们可以直接得到,是2^left - 1,加上当前这个root节点,则正好是2^left。再对右子树进行递归统计。
left != right。说明此时最后一层不满,但倒数第二层已经满了,可以直接得到右子树的节点个数。同理,右子树节点+root节点,总数为2^right。再对左子树进行递归查找。
如何计算2^left,最快的方法是移位计算,因为运算符的优先级问题,记得加括号哦。
#include <iostream>
#include <cassert>
using namespace std;
/// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
/// Recursion
/// Time Complexity: O(h^2) where h is the height of the tree
/// Space Complexity: O(h)
class Solution {
public:
int countNodes(TreeNode* root) {
if(root == NULL)
return 0;
int leftLeft = leftHeight(root->left);
int leftRight = rightHeight(root->left);
if(leftLeft == leftRight)
return 1 + ((1<<leftLeft) - 1) + countNodes(root->right);
assert(leftLeft == leftRight + 1);
return 1 + ((1<<leftRight) - 1) + countNodes(root->left);
}
private:
int leftHeight(TreeNode* root){
if(root == NULL)
return 0;
return 1 + leftHeight(root->left);
}
int rightHeight(TreeNode* root){
if(root == NULL)
return 0;
return 1 + rightHeight(root->right);
}
};
int main() {
TreeNode* root = new TreeNode(1);
TreeNode* left = new TreeNode(2);
root->left = left;
TreeNode* right = new TreeNode(3);
root->right = right;
TreeNode* leftleft = new TreeNode(4);
root->left->left = leftleft;
TreeNode* leftright = new TreeNode(5);
root->left->right = leftright;
TreeNode* rightleft = new TreeNode(6);
root->right->left = rightleft;
cout << Solution().countNodes(root) << endl;
return 0;
}
改进
#include <iostream>
#include <cassert>
using namespace std;
/// Definition for a binary tree node.
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
/// Recursion
/// A very small improvement based on solution1
/// No repeat calculation for leftLeft:)
///
/// Time Complexity: O(h^2) where h is the height of the tree
/// Space Complexity: O(h)
class Solution {
public:
int countNodes(TreeNode* root) {
return countNodes(root, -1);
}
private:
int countNodes(TreeNode* root, int left){
if(root == NULL)
return 0;
int leftLeft = left == -1 ? leftHeight(root->left) : left;
int leftRight = rightHeight(root->left);
if(leftLeft == leftRight)
return 1 + ((1<<leftLeft) - 1) + countNodes(root->right, -1);
assert(leftLeft == leftRight + 1);
return 1 + ((1<<leftRight) - 1) + countNodes(root->left, leftLeft - 1);
}
int leftHeight(TreeNode* root){
if(root == NULL)
return 0;
return 1 + leftHeight(root->left);
}
int rightHeight(TreeNode* root){
if(root == NULL)
return 0;
return 1 + rightHeight(root->right);
}
};
int main() {
TreeNode* root = new TreeNode(1);
TreeNode* left = new TreeNode(2);
root->left = left;
TreeNode* right = new TreeNode(3);
root->right = right;
TreeNode* leftleft = new TreeNode(4);
root->left->left = leftleft;
TreeNode* leftright = new TreeNode(5);
root->left->right = leftright;
TreeNode* rightleft = new TreeNode(6);
root->right->left = rightleft;
cout << Solution().countNodes(root) << endl;
return 0;
}