leetcode -- Count Complete Tree Nodes -- 重点。BFS

https://leetcode.com/problems/count-complete-tree-nodes/

思路1 递归

参考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

思路2 BFS

这里参考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有 2h1 个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里面提到了 2hsub1 ,这里其实要看成root的左子树高度为 hsub ,如果为full bt,那么最后一层的node数目应该就为 2depth1 或者是 2hsub , 这里 hsub 就是刚刚定义的左子树的depth。如果最后一行的最后一个node在root的右子树,那么我们就可以加上左子树最后一行所有的node,就是 2hsub 的一半,因为要排除右子树最后一行残缺的node,所以为 2hsub1 .

在下面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就可以了。然后继续递归。

下图给了一个case的算法模拟图。
这里写图片描述

这里要注意的是,在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(01) =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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值