https://leetcode.com/problems/count-complete-tree-nodes/
参考http://www.tangjikai.com/algorithms/leetcode-222-complete-tree-nodes
class Solution(object):
def getLeftDepth(self, root, level):
level = 0
while root:
root = root.left
level += 1
return level
def getRightDepth(self, root, level):
level = 0
while root:
root = root.right
level += 1
return level
def countNodes(self, root):
""" :type root: TreeNode :rtype: int """
if not root: return 0
ld = self.getLeftDepth(root,0)
rd = self.getRightDepth(root,0)
#print (ld,rd)
if ld == rd:
return (1<<ld) - 1
else:
return self.countNodes(root.left) + self.countNodes(root.right) + 1
这里参考http://yucoding.blogspot.hk/2015/10/leetcode-question-question-count.html
我们需要注意一下BT的一些概念,depth 就是所有节点中最大的level数,level是从1开始计数的,即2层的full bt就只有3个节点,不能把depth看成了整个树的高度。所以depth为h的full bt有 2h−1 个node
这里最重要的就是求最后一层的node个数。先想象是个full binary tree, 那么最后一层中node存在的设为1,不存在的设为0. 就有了[111111, …, 00000]的数组,然后我们的任务就是找到最后一个1,进而可以得到有多少个1
第一次BS的start point的是left most node, end point 为right most node in the last level, and it can be empty node. 然后 middle node 就是 left most node in the right subtree. 然后循环。。。。。
这个思路也值得参考https://segmentfault.com/a/1190000003818177
yu’s coding 的code如下:
class Solution(object):
def findSplitDepth(self, root):
if not root:
return 0
else:
root = root.right
dep = 0
while root:
root = root.left
dep += 1
return dep
def countNodes(self, root):
""" :type root: TreeNode :rtype: int """
if not root:
return 0
dep = 1
tmp = root
while tmp.left:#就是计算root整个树的depth
dep += 1
tmp = tmp.left
cur_root = root
cur_dep = 1
res = 0
while cur_dep < dep:
dd = self.findSplitDepth(cur_root)
if dd + cur_dep == dep:
cur_root = cur_root.right
res += pow(2, dd-1)
cur_dep += 1
else:
cur_root = cur_root.left
cur_dep += 1
return pow(2, dep-1) + res
yucoding里面提到了 2hsub−1 ,这里其实要看成root的左子树高度为 hsub ,如果为full bt,那么最后一层的node数目应该就为 2depth−1 或者是 2hsub , 这里 hsub 就是刚刚定义的左子树的depth。如果最后一行的最后一个node在root的右子树,那么我们就可以加上左子树最后一行所有的node,就是 2hsub 的一半,因为要排除右子树最后一行残缺的node,所以为 2hsub−1 .
在下面code中,dd表示的是以root.right为root的树的左子树的depth,cur_depth表示已经递归掉得depth,如果最后一行的最后一个点在右子树,那么dd + cur_depth == depth, 即对于root来说左子树的depth与右子树一样。我们就可以把cur_root改成root.right, 并把root的左子树最后一行的node数目算出来,(因为这个时候root的左子树已经是full bt). 这里因为dd + cur_depth == depth 使得,dd其实也是root左子树的depth,所以可以就用 2dd 再除以2,算出左子树最后一行node书数目。如果dd + cur_depth != depth, 那么就是说最后一行的最后一个node在左子树,那么cur_root = root.left, 然后递归深度cur_depth += 1就可以了。然后继续递归。
这里要注意的是,在yu’coding里面的code中,res是用来计算最后一层的node数目,但是因为root递归到最后一行最后一个node的时候,cur_depth == depth了,程序跳出,所以res其实是少算了一个最后一行的node,所以最后一行node数目应该是res + 1。然后加上depth - 1的full bt的数目power(2, depth-1) - 1. 这样加起来就是 power(2, depth-1) + res.
为了便于理解,我改造了一下yu’coding里面的code,使得res会把最后一行最后一个node算进去, 就是计算最后一行所有的node数目。将while cur_depth < depth 改成 while cur_depth <= depth. 并且还要在计算res的时候,如果dd等于0的话res应该加1. 否则对于[1], 这样的输入case,dd = 0, res会加上 2(0−1) =0.5.
改造后的code 如下:
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, x):
# self.val = x
# self.left = None
# self.right = None
class Solution(object):
def findSplitDepth(self, root):
if not root:
return 0
else:
root = root.right
dep = 0
while root:
root = root.left
dep += 1
return dep
def countNodes(self, root):
""" :type root: TreeNode :rtype: int """
if not root:
return 0
dep = 1
tmp = root.left
while tmp:#这样求depth更好理解
dep += 1
tmp = tmp.left
cur_root = root
cur_dep = 1
res = 0
while cur_dep <= dep:# add equal case
dd = self.findSplitDepth(cur_root)
if dd + cur_dep == dep:
cur_root = cur_root.right
if dd != 0:#revised by me
#res += pow(2, dd-1)
res += 1<<(dd - 1)#用位操作更快
else:#revised by me
res += 1
cur_dep += 1
else:
cur_root = cur_root.left
cur_dep += 1
return (1<<(dep - 1)) - 1 + res#revised by me