LeetCode 222. Count Complete Tree Nodes - 二分查找(Binary Search)系列题13

Posted CP Coding

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 222. Count Complete Tree Nodes - 二分查找(Binary Search)系列题13相关的知识,希望对你有一定的参考价值。

Given the root of a complete binary tree, return the number of the nodes in the tree.

According to Wikipedia, every level, except possibly the last, is completely filled in a complete binary tree, and all nodes in the last level are as far left as possible. It can have between 1 and 2^h nodes inclusive at the last level h.

Design an algorithm that runs in less than O(n) time complexity.

Example 1:

Input: root = [1,2,3,4,5,6]
Output: 6

Example 2:

Input: root = []
Output: 0

Example 3:

Input: root = [1]
Output: 1

Constraints:

  • The number of nodes in the tree is in the range [0, 5 * 104].
  • 0 <= Node.val <= 5 * 104
  • The tree is guaranteed to be complete.

题目要求一棵完全二叉树的节点个数。所谓完全二叉树就是树中除了最后一层其他每层的节点都是满的,而最后一层的节点是集中在左部即从左到右挨个分布的。根据完全二叉树的特点,我们可以直接算出各层(除了最后一层)的节点个数。

对一个高度为h(第一层高度为1)的完全二叉树,前h - 1层的节点个数是2^0 + 2^1 + ... + 2^(h - 2) = 2^(h - 1) - 1。而最后一层由于可能不是满的,节点个数并确定,但可以确定个数是在1到2^(h-1)范围内。也就说只要能求出最后一层节点个数,就能知道整棵树的节点总个数。

因此本题就变成了求最后一层节点个数,它是1到2^(h-1)范围内的某个数,这很容易想到用二分查找法。把区间[1, 2^(h-1)]从中间分成左右两个区间,然后判断中点第(1 + 2^(h-1))//2个节点是否存在,如果存在说明左半区间是满点,则继续在右半区间查找;如果不存在说明左半区间不是满的而右半区间肯定是空的,则继续在左半区间查找。

到此,本题该如何用二分查找法已经很明确了,难点就变成了该如何快速地判断最后一层的某一个节点是存在。我们会发现一棵树(h > 1)的最后一层的中间节点是根节点的左子树的最右边的那个节点。抓住这个特点就可以快速地判断最后一层的中间节点是否存在。

class Solution:
    def countNodes(self, root: Optional[TreeNode]) -> int:
        h = self.height(root)
        if h <= 1:
            return h
        
        #前h-1层的总个数
        res = 2 ** (h - 1) - 1
        
        #最后一层个数介于[1, 2 ** (h - 1)]之间
        l, r = 1, 2 ** (h - 1)
        
        while l <= r:
            #并判断最后一层中间那个节点是否存在
            mid = l + (r - l) // 2
            if self.isExist(root, h): #如存在则继续查找右半区间即右子树
                l = mid + 1
                if root: 
                    root = root.right
            else:   #如不存在则继续查找左半区间即左子树
                r = mid - 1
                if root:
                    root = root.left
            #左右半区间分别对应于左右子树,子树高度减1
            h -= 1

            #查找到最后,l是最后一层第一不存在的节点,因此最后一层个数是l - 1
        return res + l - 1
    
    def height(self, root):
        res = 0
        while root:
            root = root.left
            res += 1
        
        return res
    
    #判断一棵高度为h的树的最后一层的中间节点是否存在
    def isExist(self, root, h):
        #只有一层时即最后一层,直接判断该节点是否存在
        if h == 1:
            return root != None
        
        #如果不只一层则最后一层的中间节点是左子树的最靠右的那个节点
        root = root.left
        h -= 1
        for i in range(h - 1):
            root = root.right
        
        return root != None

 

以上是关于LeetCode 222. Count Complete Tree Nodes - 二分查找(Binary Search)系列题13的主要内容,如果未能解决你的问题,请参考以下文章

LeetCode222——Count Complete Tree Nodes

Leetcode 222. Count Complete Tree Nodes

LeetCode OJ 222. Count Complete Tree Nodes

[LeetCode] 222. Count Complete Tree Nodes Java

[Leetcode] Binary search -- 222. Count Complete Tree Nodes

leetcode 222.Count Complete Tree Nodes