[LeetCode] Count Complete Tree Nodes 求完全二叉树的节点个数
Given a complete binary tree, count the number of nodes.
Note:
Definition of a complete binary tree from Wikipedia:
In a complete binary tree every level, except possibly the last, is completely filled, and all nodes in the last level are as far left as possible. It can have between 1 and 2h nodes inclusive at the last level h.
Example:
Input:
1
/ \
2 3
/ \ /
4 5 6 Output: 6
这道题给定了一棵完全二叉树,让我们求其节点的个数。很多人分不清完全二叉树和满二叉树的区别,下面让我们来看看维基百科上对二者的定义:
A Complete Binary Tree (CBT) is a binary tree in which every level, except possibly the last, is completely filled, and all nodes are as far left as possible.
对于一颗二叉树,假设其深度为d(d>1)。除了第d层外,其它各层的节点数目均已达最大值,且第d层所有节点从左向右连续地紧密排列,这样的二叉树被称为完全二叉树;
换句话说,完全二叉树从根结点到倒数第二层满足完美二叉树,最后一层可以不完全填充,其叶子结点都靠左对齐。
A Perfect Binary Tree(PBT) is a tree with all leaf nodes at the same depth. All internal nodes have degree 2.
二叉树的第i层至多拥有 个节点数;深度为k的二叉树至多总共有
个节点数,而总计拥有节点数匹配的,称为“满二叉树”;
A Full Binary Tree (FBT) is a tree in which every node other than the leaves has two children.
换句话说,所有非叶子结点的度都是2。(只要你有孩子,你就必然是有两个孩子。)

其实这道题的最暴力的解法就是直接用递归来统计结点的个数,根本不需要考虑什么完全二叉树还是完美二叉树,递归在手,遇 tree 不愁。直接一行搞定碉堡了,这可能是我见过最简洁的 brute force 的解法了吧,参见代码如下:
解法一:
class Solution {
public:
int countNodes(TreeNode* root) {
return root ? ( + countNodes(root->left) + countNodes(root->right)) : ;
}
};
我们还是要来利用一下完全二叉树这个条件,不然感觉对出题者不太尊重。通过上面对完全二叉树跟完美二叉树的定义比较,可以看出二者的关系是,完美二叉树一定是完全二叉树,而完全二叉树不一定是完美二叉树。那么这道题给的完全二叉树就有可能是完美二叉树,若是完美二叉树,节点个数很好求,为2的h次方减1,h为该完美二叉树的高度。若不是的话,只能老老实实的一个一个数结点了。思路是由 root 根结点往下,分别找最靠左边和最靠右边的路径长度,如果长度相等,则证明二叉树最后一层节点是满的,是满二叉树,直接返回节点个数,如果不相等,则节点个数为左子树的节点个数加上右子树的节点个数再加1(根节点),其中左右子树节点个数的计算可以使用递归来计算,参见代码如下:
解法二:
class Solution {
public:
int countNodes(TreeNode* root) {
int hLeft = , hRight = ;
TreeNode *pLeft = root, *pRight = root;
while (pLeft) {
++hLeft;
pLeft = pLeft->left;
}
while (pRight) {
++hRight;
pRight = pRight->right;
}
if (hLeft == hRight) return pow(, hLeft) - ;
return countNodes(root->left) + countNodes(root->right) + ;
}
};
我们也可以全用递归的形式来解,如下所示:
解法三:
class Solution {
public:
int countNodes(TreeNode* root) {
int hLeft = leftHeight(root);
int hRight = rightHeight(root);
if (hLeft == hRight) return pow(, hLeft) - ;
return countNodes(root->left) + countNodes(root->right) + ;
}
int leftHeight(TreeNode* root) {
if (!root) return ;
return + leftHeight(root->left);
}
int rightHeight(TreeNode* root) {
if (!root) return ;
return + rightHeight(root->right);
}
};
这道题还有一个标签是 Binary Search,但是在论坛上看了一圈下来,并没有发现有经典的二分搜索的写法,只找到了下面这个类似二分搜索的解法,感觉应该不算严格意义上的二分搜素法吧,毕竟 left,right 变量和 while 循环都没有,只是隐约有点二分搜索法的影子在里面,即根据条件选左右分区。首先我们需要一个 getHeight 函数,这是用来统计当前结点的左子树的最大高度的,因为一直走的是左子结点,若当前结点不存在,则返回 -1。我们对当前结点调用 getHeight 函数,得到左子树的最大高度h,若为 -1,则说明当前结点不存在,直接返回0。否则就对右子结点调用 getHeight 函数,若返回值为 h-1,说明左子树是一棵完美二叉树,则左子树的结点个数是 2^h-1 个,再加上当前结点,总共是 2^h 个,即 1<<h,此时再加上对右子结点调用递归函数的返回值即可。若对右子结点调用 getHeight 函数的返回值不为 h-1,说明右子树一定是完美树,且高度为 h-1,则总结点个数为 2^(h-1)-1,加上当前结点为 2^(h-1),即 1<<(h-1),然后再加上对左子结点调用递归函数的返回值即可。这样貌似也算一种二分搜索法吧,参见代码如下:
解法四:
class Solution {
public:
int countNodes(TreeNode* root) {
int res = , h = getHeight(root);
if (h < ) return ;
if (getHeight(root->right) == h - ) return ( << h) + countNodes(root->right);
return ( << (h - )) + countNodes(root->left);
}
int getHeight(TreeNode* node) {
return node ? ( + getHeight(node->left)) : -;
}
};
我们也可以写成迭代的形式,用一个 while 循环,感觉好处是调用 getHeight 函数的次数变少了,因为开头计算的高度h可以一直用,每下一层后,h自减1即可,参见代码如下:
解法五:
class Solution {
public:
int countNodes(TreeNode* root) {
int res = , h = getHeight(root);
if (h < ) return ;
while (root) {
if (getHeight(root->right) == h - ) {
res += << h;
root = root->right;
} else {
res += << (h - );
root = root->left;
}
--h;
}
return res;
}
int getHeight(TreeNode* node) {
return node ? ( + getHeight(node->left)) : -;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/222
类似题目:
Closest Binary Search Tree Value
参考资料:
https://leetcode.com/problems/count-complete-tree-nodes/
LeetCode All in One 题目讲解汇总(持续更新中...)
[LeetCode] Count Complete Tree Nodes 求完全二叉树的节点个数的更多相关文章
- [LeetCode] 222. Count Complete Tree Nodes 求完全二叉树的节点个数
Given a complete binary tree, count the number of nodes. Note: Definition of a complete binary tree ...
- 222. Count Complete Tree Nodes -- 求完全二叉树节点个数
Given a complete binary tree, count the number of nodes. Definition of a complete binary tree from W ...
- LeetCode OJ:Count Complete Tree Nodes(完全二叉树的节点数目)
Given a complete binary tree, count the number of nodes. Definition of a complete binary tree from W ...
- 【leetcode】222. Count Complete Tree Nodes(完全二叉树)
Given the root of a complete binary tree, return the number of the nodes in the tree. According to W ...
- LeetCode Count Complete Tree Nodes
原题链接在这里:https://leetcode.com/problems/count-complete-tree-nodes/ Given a complete binary tree, count ...
- LeetCode——Count Complete Tree Nodes
Description: Given a complete binary tree, count the number of nodes. In a complete binary tree ever ...
- leetcode 958. Check Completeness of a Binary Tree 判断是否是完全二叉树 、222. Count Complete Tree Nodes
完全二叉树的定义:若设二叉树的深度为h,除第 h 层外,其它各层 (1-h-1) 的结点数都达到最大个数,第 h 层所有的结点都连续集中在最左边,这就是完全二叉树. 解题思路:将树按照层进行遍历,如果 ...
- leetcode面试准备:Count Complete Tree Nodes
1 题目 Given a complete binary tree, count the number of nodes. In a complete binary tree every level, ...
- 【LeetCode】222. Count Complete Tree Nodes 解题报告(Python)
[LeetCode]222. Count Complete Tree Nodes 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个 ...
随机推荐
- Web安全相关(二):跨站请求伪造(CSRF/XSRF)
简介 CSRF(Cross-site request forgery跨站请求伪造,也被称为“One Click Attack”或者Session Riding,通常缩写为CSRF或者XSRF,是一种对 ...
- Markdown通用的常用语法说明
前言 Markdown 是一种轻量级的 标记语言,语法简洁明了.学习容易,还具有其他很多优点,目前被越来越多的人用来写作使用. Markdown具有一系列衍生版本,用于扩展Markdown的功能(如表 ...
- C#基础知识八之访问修饰符
1. 类的访问修饰符 修饰符 访问权限 无或者internal 只能在同一个程序集中访问类 public 同一个程序集或引用该程序集的外部都可访问类 abstract或internal abstra ...
- 带你玩转Visual Studio
带你玩转Visual Studio 带你新建一个工程 工程目录下各文件的含义 解决方案与工程 在这之前先了解一个概念:解决方案与工程. 解决方案(Solution):一个大型项目的整体的工作环境: 工 ...
- HTML5学习笔记之History API
这系列文章主要是学习Html5相关的知识点,以学习API知识点为入口,由浅入深的引入实例,让大家一步一步的体会"h5"能够做什么,以及在实际项目中如何去合理的运用达到使用自如,完美 ...
- ASP.NET从MVC5升级到MVC6 RC2 总目录 - 发布在RC2Release之后
序言 随着MVC6RC2的推出,MVC6的脚步越来越近了.但是在我们的手里,有大批量的MVC5的项目.如何将MVC5升级到MVC6,将是一个很大的课题.微软官方暂时没有一个升级指导,或者一个迁移工具, ...
- java中如何实现多态
复习基础知识 多态,就是重载和重写.重载发生在一个类中.重写发生在子类,意思就是子类重写父类相同名称的方法.刚学语言有的东西,不必搞得那么清楚,只有知道怎么用就行了,有的问题你要想真正把它搞得很懂,短 ...
- django 1.10 CSRF验证失败的解决过程
最近工作闲,没事自学django,感觉这个最烦的就是各版本提供的api函数经常有变化,不是取消了就是参数没有了,网上搜到的帖子也没说明用的是什么版本的django,所以经常出现搬运过来的代码解决不了问 ...
- 《简单的自定义DropDatePicker》-- UIPopoverController 和 代理 以及 Block 实现。
最近做项目为了方便项目使用,自定义的空间 写的比较粗糙.欢迎大家批评指正.以上为在项目中的实际应用 // DropDownDatePicker.h // DropDownDatePickerDemo ...
- iOS类中的属性设置背景色(统一)
unsigned int count; objc_property_t *properties = class_copyPropertyList([self class], &count); ...