题目链接:222. Count Complete Tree Nodes
题目大意:统计一棵完全二叉树的结点数
注意点:
- 完全二叉树的性质:叶子结点只可能在该二叉树最大的两层上出现,而且结点先放满左子树再放右子树。
- 使用直接扫描结点方法来统计,时间复杂度过高,显然不适合。
- 要根据完全二叉树的性质来设计算法。
一.算法设计
如何利用完全二叉树的性质来进行统计呢?我们可以利用完全二叉树的子树仍然是完全二叉树的性质来设计递归算法,一层一层地往下统计。
我们先对根节点的左子树以及右子树都进行左深度统计。
一棵完全二叉树只有两种情况,当左子树的左深度等于右子树的左深度,那么左子树一定是满二叉树;相反,当左子树的左深度不等于右子树的左深度,那么右子树一定是满二叉树。
如图所示:
所以,我们可以根据这个性质来设计递归算法,仅需要判断左子树与右子树的左深度是否相同。
而一棵满二叉树的结点数为 2d−1 2 d − 1 , d为树的深度。
二.实现代码
/**
* 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;
//计算左子树以及右子树的左深度
int l_depth = getDepth(root->left);
int r_depth = getDepth(root->right);
if(l_depth == r_depth){
//返回满左子树的结点 + 根结点 + 递归统计右子树结点
return pow(2,l_depth) + countNodes(root->right);
}
else{
//返回满右子树的结点 + 根结点 + 递归统计左子树结点
return pow(2,r_depth) + countNodes(root->left);
}
}
//计算树的左深度
int getDepth(TreeNode* root){
TreeNode* temp = root;
int count = 0;
while(temp != NULL){
temp = temp->left;
count++;
}
return count;
}
};
三.从别人的代码中学习
在AC以后,当然少不了比较时间复杂度,结果发现可以写出更好的代码。利用树结点结构体有一个值的性质来直接遍历,遍历完成后修改该值,这算是比较巧妙的方法,当树结点的值不能被修改时,实用性不是太好。当然,这只是一道算法的题。
class Solution {
public:
int countNodes(TreeNode* root) {
if(root == NULL) return 0;
if(root->val != -1){
root->val = -1;
return 1 + countNodes(root->left) + countNodes(root->right);
}
return 0;
}
};