![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e4071352a208f161d6a37ef8fb3ab5ba.png)
1. 法一:利用完全二叉树性质,进行递归二分查找
解题思路:时间复杂度O(
l
o
g
2
n
log_2{n}
log2n),空间复杂度O(n),因为递归底层需要栈来实现 |
---|
- 完全二叉树:除去最后一层,剩下的是满二叉树。其中满二叉树也是完全二叉树的一种。
- 完全二叉树最后一层的叶子结点,必须是连续的
- 最后一层如果不满,假设最后一层只有一个叶子结点,也一定是左结点。因为它必须连续。所以,
缺也不会缺左结点
- 满二叉树的结点个数为:
2
高度
−
1
2^{高度}-1
2高度−1,例如一个满二叉树高的为5,那么一共有
2
5
−
1
=
31
2^5-1 = 31
25−1=31个结点
- 所以,我们依次从根节点开始遍历
- 如果当前结点代表着一棵满二叉树(完全二叉树前提下,左子树高的 = 右子树高度),那么代表左子树一定是满的。而右子树未必是满的,因为只是高度一样,完全二叉树只能保证,缺也不会缺左结点。而现在有右节点,说明左节点不缺
- 因此左子树高的 = 右子树高度,可以直接跳过左子树,用公式
2
左子树高度
−
1
2^{左子树高度}-1
2左子树高度−1计算左子树的结点个数,然后算上当前根节点+1,最终为
2
左子树高度
2^{左子树高度}
2左子树高度个结点
- 但是如果左子树高的 != 右子树高度,说明最后一层不满,但是除去最后一层,其余的一定为满二叉树,所以右子树一定是满二叉树,只不过比左子树高的少1而已
- 因此左子树高的 != 右子树高度时:右子树的结点个数+当前结点 =
2
右子树高度
2^{右子树高度}
2右子树高度
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e369b38acaa503f3f8bbf05cc9939478.png)
class Solution {
public int countNodes(TreeNode root) {
if(root == null) return 0;
int left = countLevel(root.left);
int right = countLevel(root.right);
if(left == right)
return countNodes(root.right) + (1 << left);
else
return countNodes(root.left) + (1 << right);
}
private int countLevel(TreeNode root){
int level = 0;
while(root != null){
level++;
root = root.left;
}
return level;
}
}
2. 二分查找+位运算
解题思路:时间复杂度O(
l
o
g
2
n
log_2{n}
log2n),空间复杂度O(1) |
---|
- 先统计深度
- 那么倒数第二层必然是满二叉树。
- 最后一层不确定有多少个
- 我们对其进行二分查找。看看最后一个叶子结点,在最后一层哪个位置
- 最后将倒数第二层的满二叉树+最后一层的结点个数 = 整个数的结点个数
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/1caaa0b9cca6b5c0e1d27d8bb676cc43.png)
class Solution {
public int countNodes(TreeNode root) {
if (root == null) {
return 0;
}
int level = 0;
TreeNode node = root;
while (node.left != null) {
level++;
node = node.left;
}
int low = 1 << level, high = (1 << (level + 1)) - 1;
while (low < high) {
int mid = (high - low + 1) / 2 + low;
if (exists(root, level, mid)) {
low = mid;
} else {
high = mid - 1;
}
}
return low;
}
public boolean exists(TreeNode root, int level, int k) {
int bits = 1 << (level - 1);
TreeNode node = root;
while (node != null && bits > 0) {
if ((bits & k) == 0) {
node = node.left;
} else {
node = node.right;
}
bits >>= 1;
}
return node != null;
}
}