本文主要是介绍【经典算法】LeetCode 222. 完全二叉树的节点个数(Java/C/Python3实现含注释说明,Easy),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
作者主页: 🔗进朱者赤的博客
精选专栏:🔗经典算法
作者简介:阿里非典型程序员一枚 ,记录在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法(公众号同名)
❤️觉得文章还不错的话欢迎大家点赞👍➕收藏⭐️➕评论,💬支持博主,记得点个大大的
关注
,持续更新🤞
————————————————-
题目描述
给定一个完全二叉树,计算树的节点个数。完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h 个节点。
原题:LeetCode 222
思路及实现
方式一:递归遍历
思路
递归遍历整棵树,每个节点都返回其子树的大小,最终相加即为整个树的大小。
代码实现
Java版本
// 假设树的节点定义如下
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}public class Solution {public int countNodes(TreeNode root) {if (root == null) return 0;return 1 + countNodes(root.left) + countNodes(root.right);}
}
说明:这是最基本的递归方法,简单易懂但效率不高,因为会遍历整个树。
C语言版本
// 假设树的节点定义如下
struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
};int countNodes(struct TreeNode* root) {if (root == NULL) return 0;return 1 + countNodes(root->left) + countNodes(root->right);
}
说明:与Java版本类似,只是语法不同。
Python3版本
# 假设树的节点定义如下
class TreeNode:def __init__(self, val=0, left=None, right=None):self.val = valself.left = leftself.right = rightclass Solution:def countNodes(self, root: TreeNode) -> int:if not root: return 0return 1 + self.countNodes(root.left) + self.countNodes(root.right)
说明:Python版本的实现与Java和C类似。
Golang版本
// 假设树的节点定义如下
type TreeNode struct {Val intLeft *TreeNodeRight *TreeNode
}func countNodes(root *TreeNode) int {if root == nil {return 0}return 1 + countNodes(root.Left) + countNodes(root.Right)
}
说明:Golang版本的实现与上述语言类似。
复杂度分析
- 时间复杂度:O(N),其中N为树的节点个数。每个节点都遍历了一次。
- 空间复杂度:O(H),其中H为树的高度。递归调用栈的深度最大为树的高度。
方式二:二分查找+递归
思路
利用完全二叉树的性质,先找到树的高度,然后利用二分查找确定左子树或右子树中最后一层满二叉树的节点个数,递归计算剩余部分。
以下是按照给定思路实现的完全二叉树节点数统计的Java、C、Python3和Go语言的代码,以及相应的复杂度分析。
代码实现
Java
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode(int x) { val = x; }
}public class Solution {public int countNodes(TreeNode root) {if (root == null) return 0;int leftHeight = getHeight(root.left);int rightHeight = getHeight(root.right);if (leftHeight == rightHeight) {// 左子树是满二叉树return (1 << leftHeight) + countNodes(root.right);} else {// 左子树不是满二叉树,递归计算左子树return 1 + countNodes(root.left);}}private int getHeight(TreeNode node) {if (node == null) return 0;return 1 + getHeight(node.left);}
}
C
#include <stdio.h>
#include <stdlib.h>typedef struct TreeNode {int val;struct TreeNode *left;struct TreeNode *right;
} TreeNode;int getHeight(TreeNode* node) {if (node == NULL) return 0;return 1 + getHeight(node->left);
}int countNodes(TreeNode* root) {if (root == NULL) return 0;int leftHeight = getHeight(root->left);int rightHeight = getHeight(root->right);if (leftHeight == rightHeight) {return (1 << leftHeight) + countNodes(root->right);} else {return 1 + countNodes(root->left);}
}
Python3
class TreeNode:def __init__(self, x):self.val = xself.left = Noneself.right = Nonedef getHeight(node):if node is None:return 0return 1 + getHeight(node.left)def countNodes(root):if root is None:return 0leftHeight = getHeight(root.left)rightHeight = getHeight(root.right)if leftHeight == rightHeight:return (1 << leftHeight) + countNodes(root.right)else:return 1 + countNodes(root.left)
Go
package mainimport ("fmt""math"
)type TreeNode struct {Val intLeft *TreeNodeRight *TreeNode
}func getHeight(node *TreeNode) int {if node == nil {return 0}return 1 + getHeight(node.Left)
}func countNodes(root *TreeNode) int {if root == nil {return 0}leftHeight := getHeight(root.Left)rightHeight := getHeight(root.Right)if leftHeight == rightHeight {return int(math.Pow(2, float64(leftHeight))) + countNodes(root.Right)} else {return 1 + countNodes(root.Left)}
}func main() {// Test code// ...
}
复杂度分析
-
时间复杂度:O(N log N),其中 N 是树的节点数。在最坏情况下,当树接近满二叉树时,每次递归调用
getHeight
都会遍历树的一部分,直到找到完全二叉树的边界。由于二分查找的性质,递归调用的次数为 O(log N),但每次递归可能需要遍历树的大部分节点,因此总的时间复杂度为 O(N log N)。然而,在平均情况下,由于使用了二分查找,性能会优于最坏情况。 -
空间复杂度:O(H),其中 H 是树的高度。这是由递归调用栈的深度决定的。在完全二叉树中,H 通常远小于 N(节点数),但在最坏情况下(树接近满二叉树),H 接近于 log N。因此,空间复杂度在最坏情况下为 O(log N)。
总结
以下是针对完全二叉树节点数统计的两种方式的总结:
方式 | 优点 | 缺点 | 时间复杂度 | 空间复杂度 |
---|---|---|---|---|
方式一(层次遍历) | 直观易懂,不依赖特殊性质 | 代码量较大,需要额外的空间存储队列 | O(N) | O(N)(队列空间) |
方式二(二分查找+递归) | 利用完全二叉树的性质,平均性能较好 | 递归调用栈可能较深,最坏情况下时间复杂度较高 | O(N log N) | O(H)(H为树的高度,通常小于N) |
相似题目
以下是与完全二叉树节点数统计相似的题目,这些题目可能需要类似的算法思想或者技巧来解决:
相似题目 | 难度 | 链接 |
---|---|---|
105. 从前序与中序遍历序列构造二叉树 | 中等 | LeetCode 105 |
106. 从中序与后序遍历序列构造二叉树 | 中等 | LeetCode 106 |
110. 平衡二叉树 | 简单 | LeetCode 110 |
111. 二叉树的最小深度 | 简单 | LeetCode 111 |
112. 路径总和 | 简单 | LeetCode 112 |
222. 完全二叉树的节点个数 | 中等 | LeetCode 222(本题) |
543. 二叉树的直径 | 简单 | LeetCode 543 |
572. 另一个树的子树 | 中等 | LeetCode 572 |
993. 二叉树的堂兄弟节点 | 中等 | LeetCode 993 |
104. 二叉树的最大深度 | 简单 | LeetCode 104 |
请注意,这些题目可能并不完全与完全二叉树节点数统计具有相同的解题技巧,但它们都涉及到了二叉树的遍历、性质利用、递归、DFS/BFS等常见的算法思想。
欢迎一键三连(关注+点赞+收藏),技术的路上一起加油!!!代码改变世界
关于我:阿里非典型程序员一枚 ,记录在大厂的打怪升级之路。 一起学习Java、大数据、数据结构算法(公众号同名),回复暗号,更能获取学习秘籍和书籍等
—⬇️欢迎关注下面的公众号:
进朱者赤
,认识不一样的技术人。⬇️—
这篇关于【经典算法】LeetCode 222. 完全二叉树的节点个数(Java/C/Python3实现含注释说明,Easy)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!