跳转至

222. 完全二叉树的节点个数#

问题描述#

给出一个完全二叉树,求出该树的节点个数。

说明:

完全二叉树的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。

示例:

输入: 
    1
   / \
  2   3
 / \  /
4  5 6

输出: 6

解题思路#

显然深搜广搜都可以做,

深搜
1
2
3
4
5
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        if root is None:
            return 0
        return 1 + self.countNodes(root.left) + self.countNodes(root.right)
广搜
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        if root is None:
            return 0
        q = deque([root])
        ans = 0
        while q:
            ans += 1
            node = q.popleft()
            if node.left:
                q.append(node.left)
            if node.right:
                q.append(node.right)
        return ans

但是这样就没有利用到 完全二叉树 这个条件。

对于满二叉树而言,第 \(h\) 层(根结点为第 0 层,编号为 1)的结点编号范围为 \(2^h\sim 2^{h+1}-1\)

对于完全二叉树而言,最左边的结点一定是在最后一层。

所以可以根据最后一层的结点编号范围进行二分搜索。

1
2
3
4
5
       1
   0/     \1
   2       3
 0/ \1   0/
 4   5   6

根据结点编号的二进制表示可以确定它的路径,如在上图中编号为 \(\boxed{6}\) 的二进制表示为 \(1\boxed{10}\),从二进制表示的次高位开始,为 \(1\) 表示在右子树,为 \(0\) 表示在左子树。然后判断按照该路径到达的结点是否存在即可。


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution:
    def countNodes(self, root: TreeNode) -> int:
        if root is None:
            return 0

        def ok(idx: int, h: int) -> bool:
            mask = 1 << (h - 1)  # 从次高位开始
            node = root
            while mask:
                if mask & idx:  # 为 1 表示在右子树
                    node = node.right
                else:
                    node = node.left
                mask >>= 1
            return bool(node)

        h = 0
        node = root.left
        while node:
            h += 1
            node = node.left

        lo, hi = 1 << h, (1 << (h + 1)) - 1

        while lo < hi:
            # 因为 lo=mid 可能造成死循环,
            # 故在只有两个元素时,让 mid=hi
            mid = (lo + hi + 1) // 2 
            if ok(mid, h):
                lo = mid
            else:
                hi = mid - 1

        return lo
返回顶部

在手机上阅读