题目描述
给出一个完全二叉树 ,求出节点个数
基础概念补充(完全二叉树)
在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h 个节点。
输入输出示例
题解
思路一
这个题目,其实我个人感觉不像是中等难度的题目,因为,确实过于简单
第一个想法就是,先判断节点是否为叶子节点,如果是,就返回1(只有自己一个节点)。如果不是,说明它有孩子节点,那么接下来判断,是否有右子树。如果没有,则左子树,返回1+count(left),如果有则返回1+count(left)+count(right)。
最后加一个特殊判断,就是如果root是空的,那么返回0
代码一
class Solution:
def is_leaf(self,node:TreeNode):
if ((node.left==None) and (node.right==None)):
return True
else:
return False
def countNodes(self, root: TreeNode) -> int:
if (root==None):
return 0
else:
if (self.is_leaf(root)):
return 1
else:
if root.right==None:
return 1+self.countNodes(root.left)
else:
return 1+self.countNodes(root.left)+self.countNodes(root.right)
运行结果一
显然,还有很多需要改进的地方
思路二
后来想了想,其实没必要那么麻烦判断是否有子树,直接count就行了,如果是空返回0就好了,这样应该能简化不少
代码二
class Solution:
def countNodes(self, root: TreeNode) -> int:
if (root==None):
return 0
else:
return 1+self.countNodes(root.left)+self.countNodes(root.right)
运行结果二
相比上次是有所改进,但是好像还是不够好,因为到这里还有一个未用到的条件
思路三(LeetCode官方思路)
之前提到过的未用到的条件 ,就是题目中的完全二叉树 。之前我们的算法是使用所有的二叉树的,所以必然有一些不太必要的操作,所以这次我们要利用完全二叉树的特点进行计算。
规定根节点位于第 0 层,完全二叉树的最大层数为 h。根据完全二叉树的特性可知,完全二叉树的最左边的节点一定位于最底层,因此从根节点出发,每次访问左子节点,直到遇到叶子节点,该叶子节点即为完全二叉树的最左边的节点,经过的路径长度即为最大层数 h。
非底层的第
i
i
i层,一共有
2
i
2^i
2i个节点。
底层的第
h
h
h层,可能有
[
1
,
2
h
]
[1,2^h]
[1,2h]个节点,可以在该范围内通过二分查找的方式得到完全二叉树的节点个数。
h层完全二叉树所以一共可能的节点个数为 [ 2 h , 2 h + 1 − 1 ] [2^{h},2^{h+1}-1] [2h,2h+1−1]
具体做法是,根据节点个数范围的上下界得到当前需要判断的节点个数 k,如果第 k 个节点存在,则节点个数一定大于或等于 k,如果第 k 个节点不存在,则节点个数一定小于 k,由此可以将查找的范围缩小一半,直到得到节点个数。
如何判断第 k 个节点是否存在呢?如果第 k 个节点位于第 h 层,则 k 的二进制表示包含 h+1 位,其中最高位是 1,其余各位从高到低表示从根节点到第 k 个节点的路径,0 表示移动到左子节点,1 表示移动到右子节点。通过位运算得到第 k 个节点对应的路径,判断该路径对应的节点是否存在,即可判断第 k 个节点是否存在。
代码三(自己写的代码,官方没给)
# 这里注明一下,官方并未给出python3的解答,我是自己根据官方的思路写的代码
class Solution:
def check_exist(self,root,k):
string_bin_k = str(bin(k))
for i in range(3,len(string_bin_k)):
print(string_bin_k[i])
if string_bin_k[i] == '0':
root = root.left
else:
root = root.right
if root == None:
return False
else:
return True
def get_height(self,root):
if root == None:
return 0
height = -1
while (True):
height += 1
root = root.left
if (root == None):
break
return height
def bin_search(self,min,max,root):
if min==max-1:
if self.check_exist(root,max):
return max
else:
return min
else:
k=(min+max)//2
if self.check_exist(root,k):
return self.bin_search(k,max,root)
else:
return self.bin_search(min,k,root)
def countNodes(self, root: TreeNode) -> int:
if root == None:
return 0
else:
height = self.get_height(root)
if height == 0:
return 1
else:
return self.bin_search(pow(2,height),pow(2,height+1)-1,root)
运行结果三
本以为如此复杂的逻辑会导致运行结果不理想,其实,比之前的二结果要好