完全二叉树的节点个数
题目描述
力扣链接🔗
代码解析
以普通二叉树的思路来求
递归遍历
参考二叉树深度递归遍历的思想,可以使用二叉树递归遍历模板。
二叉树深度需要比较的是左右孩子的深度最大值,而此时求得是节点数,所以左右孩子 + 1(当前节点)即为此节点得节点数。
/**
* 递归法
*
* @param root
* @return
*/
public int countNodes(TreeNode root) {
return reverse(root);
}
public int reverse(TreeNode root) {
if (root == null) { // 当为空时,表示没有节点,返回0
return 0;
}
int leftNum = reverse(root.left); // 计算左孩子的节点数
int rightNum = reverse(root.right); // 计算右孩子的节点数
return leftNum + rightNum + 1; // 左节点数 + 右节点数 + 中间节点
}
// 后序遍历简洁版(类似求深度时的求高度遍历)
public int countNodes(TreeNode root) {
if (root == null) return 0;
return 1 + countNodes(root.left) + countNodes(root.right);
}
- 时间复杂度:#card=math&code=O%28n%29&id=ITk8w)
- 空间复杂度:#card=math&code=O%28%5Clog%20n%29&id=bT26H),算上了递归系统栈占用的空间
迭代遍历
层序迭代遍历模板修改即可。
/**
* 层序遍历
* @param root
* @return
*/
public int countNodes(TreeNode root) {
if (root == null) {
return 0;
}
Queue<TreeNode> queue = new LinkedList<>();
queue.offer(root);
int num = 0;
while (!queue.isEmpty()) {
int len = queue.size();
while (len > 0) {
TreeNode node = queue.poll();
if (node.left != null) queue.offer(node.left);
if (node.right != null) queue.offer(node.right);
num++; // 节点个数加一
len--;
}
}
return num;
}
- 时间复杂度:#card=math&code=O%28n%29&id=JFWO8)
- 空间复杂度:#card=math&code=O%28n%29&id=AFR87)
完全二叉树思想
完全二叉树只有两种情况,情况一:就是满二叉树,情况二:最后一层叶子节点没有满。
对于情况一,可以直接用 2^树深度 - 1 来计算,注意这里根节点深度为1。
对于情况二,分别递归左孩子,和右孩子,递归到某一深度一定会有左孩子或者右孩子为满二叉树,然后依然可以按照情况1来计算。
如果整个树不是满二叉树,则递归整个树来求节点数,如果为满二叉树,使用满二叉树得公式求节点即可。
/**
* 完全二叉树的性质
*
* @param root
* @return
*/
public int countNodes(TreeNode root) {
if (root == null) {
return 0;
}
TreeNode leftNode = root.left;
TreeNode rightNode = root.right;
int leftDepth = 0, rightDepth = 0; // 这里初始为0是有目的的,为了下面求指数方便
// 求左孩子的深度
while (leftNode != null) {
leftNode = leftNode.left;
leftDepth++;
}
// 求右孩子的深度
while (rightNode != null) {
rightNode = rightNode.right;
rightDepth++;
}
if (leftDepth == rightDepth) { // 此时为满二叉树
return (2 << leftDepth) - 1; // 注意(2<<1) 相当于2^2,所以leftHeight初始为0
}
// 不为满二叉树则继续递归,注意加上自身节点
return countNodes(root.left) + countNodes(root.right) + 1;
}
- 时间复杂度:#card=math&code=O%28%5Clog%20n%20%C3%97%20%5Clog%20n%29&id=hkNdP)
- 空间复杂度:#card=math&code=O%28%5Clog%20n%29&id=sJLpF)
// 求左孩子的深度
while (leftNode != null) {
leftNode = leftNode.left;
leftDepth++;
}
// 求右孩子的深度
while (rightNode != null) {
rightNode = rightNode.right;
rightDepth++;
}
这段代码就是来判断是否为满二叉树,最左边深度和最右边的深度进行比较,根据满二叉树的性质。