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