题目链接:
222. 完全二叉树的节点个数
题目:
给出一个完全二叉树,求出该树的节点个数。
说明:
完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
示例:
输入:
1
/ \
2 3
/ \ /
4 5 6
输出: 6
思路:
和广大人民群众一样,我上来也是直接写出了这样一段代码(code1),然后毫无疑问的超时了QAQ…
其实我们发现code1所示代码,对于每个节点都要搜索一下左右子树才能确定最后的高度。但是这是一个完全二叉树,意味着其实对于一些节点没有必要搜索就能确定最后的高度。
超时code 1:
class Solution {
public:
int countNodes(TreeNode* root) {
if(root==NULL) return 0;
int l=countNodes(root->left);
int r=countNodes(root->right);
return l+r+1;
}
};
法一:
首先从根节点求出左子树和右子树的高度,如果左子树和右子树同样高,那么左子树一定是满二叉树,这时候总的叶子个数为:左子树的叶子个数+根节点+剩下的还未遍历的右子树叶子个数(图1左侧),而左子树叶子个数+根节点总数为:
2
d
2^d
2d,其中d为左子树的高度,这样左子树那部分的节点就没有必要继续搜索了;
如果左子树比右子树高,说明右子树一定是满二叉树,这时候总的叶子个数为:右子树的叶子个数+根节点+剩下的还未遍历的左子树叶子个数,这样右子树那部分节点就没有必要继续搜索了(见图1右侧)。
总感觉讲复杂了qwq…代码见code2
图1 完全二叉树搜索的两种情况
code 2:
class Solution {
public:
int countNodes(TreeNode* root) {
if(root==NULL) return 0;
int L=getDepth(root->left);
int R=getDepth(root->right);
if(L==R) return (1<<L)+countNodes(root->right);//两边子树高度相同,左子树+还未遍历的右子树部分,右移运算需要加括号
if(L>R) return (1<<R)+countNodes(root->left);//左边子树高度更高,说明右边子树为满二叉树,所以右子树+还没便利的左子树部分
}
int getDepth(TreeNode *root){
if(root==NULL) return 0;
int L=getDepth(root->left);
return L+1;
}
};
法二:
有点记忆化搜索的味道,将之前出现过的节点先标记成一个最小值,下次递归返回时减少搜索量。
class Solution {
public:
int countNodes(TreeNode* root) {
if(root==NULL) return 0;
if(root->val==INT_MIN) return 0;
root->val=INT_MIN;
int l=countNodes(root->left);
int r=countNodes(root->right);
return l+r+1;
}
};
思路一参考自:
https://leetcode-cn.com/problems/count-complete-tree-nodes/comments/