222、完全二叉树的节点个数
给你一棵 完全二叉树 的根节点 root ,求出该树的节点个数。
完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2h 个节点。
示例1:
输入:root = [1,2,3,4,5,6]
输出:6
示例2:
输入:root = []
输出:0
示例3:
输入:root = [1]
输出:1
思路:
很自然想到遍历整个树,统计完全二叉树的节点数
class Solution:
def countNodes(self, root: TreeNode) -> int:
if not root: return 0
queue = [root]
total = 0
while queue:
# 累加每层的节点数
total += len(queue)
queue = [n for node in queue for n in [node.left, node.right] if n]
return total
也可以先计算出树的深度,这样只要找到最后一层的节点数即可,找到最后一层的节点,可以使用二分法
class Solution:
# 计算树的深度
def getDepth(self, root):
cur, dep = root, 0
while cur.left:
cur, dep = cur.left, dep + 1
return dep
# 判断位置是否有节点
# 最后一层的结点位置为 2**depth 至 2**(depth + 1) - 1
# 可以看到除了第一个高位外,其余位置代表着该节点在树的走向,比如11的二进制为1011,后面三位为011,那么代表着左右右节点方向
# 这样我们可以通过按位与的方式获取当前是指向左子节点还是右子节点
# 将当前比较的位设置为1,其他位置为0即可
def hasNode(self, root, index, depth):
bit = 1 << (depth - 1)
cur = root
while depth > 0:
if bit & index > 0:
cur = cur.right
else:
cur = cur.left
depth -= 1
bit = bit >> 1
return cur != None
def countNodes(self, root: TreeNode) -> int:
if not root: return 0
dep = self.getDepth(root)
print(dep)
start, end = 1 << dep, (1 << (dep + 1)) - 1
# 使用二分法找到最后一个节点
while start < end:
mid = (start + end + 1) >> 1
if self.hasNode(root, mid, dep):
start = mid
else:
end = mid - 1
return start
919、完全二叉树插入器
完全二叉树 是每一层(除最后一层外)都是完全填充(即,节点数达到最大)的,并且所有的节点都尽可能地集中在左侧。
设计一种算法,将一个新节点插入到一个完整的二叉树中,并在插入后保持其完整。
实现 CBTInserter 类:
- CBTInserter(TreeNode root) 使用头节点为 root 的给定树初始化该数据结构;
- CBTInserter.insert(int v) 向树中插入一个值为 Node.val == val的新节点 TreeNode。使树保持完全二叉树的状态,并返回插入节点 TreeNode 的父节点的值;
- CBTInserter.get_root() 将返回树的头节点。
思路:
完全二叉树需要上一层完全填充后再插入下一层,可以通过层序遍历,记录最后已经完全填充的层,找到下一层还未填充的位置,那么插入的时候,只需要在指定位置继续填充即可。
class CBTInserter:
def __init__(self, root: TreeNode):
self.root = root
# 层node队列
self.queue = [self.root]
self.index = 0
while self.queue:
# 遍历层,找到未完全插入的下标
for i, node in enumerate(self.queue):
if not node.left or not node.right:
self.index = i
return
self.queue = [n for node in self.queue for n in [node.left, node.right] if n]
# 插入的时候,获取未插入完全插入的节点
# 按照左子节点,右子节点的顺序插入
# 如果是右子节点,判断是否该层已经插入完成,如果已经插入完成,更新队列为下一层结点
def insert(self, v: int) -> int:
cur = self.queue[self.index]
if not cur.left:
cur.left = TreeNode(v)
return cur.val
if not cur.right:
cur.right = TreeNode(v)
self.index += 1
if self.index > len(self.queue) - 1:
self.index = 0
self.queue = [n for node in self.queue for n in [node.left, node.right] if n]
return cur.val
# 返回根节点
def get_root(self) -> TreeNode:
return self.root
958、二叉树的完全性校验
给定一个二叉树的 root ,确定它是否是一个 完全二叉树 。
在一个 完全二叉树 中,除了最后一个关卡外,所有关卡都是完全被填满的,并且最后一个关卡中的所有节点都是尽可能靠左的。它可以包含 1 到 2h 节点之间的最后一级 h 。
示例1:
输入:root = [1,2,3,4,5,6]
输出:true
解释:最后一层前的每一层都是满的(即,结点值为 {1} 和 {2,3} 的两层),且最后一层中的所有结点({4,5,6})都尽可能地向左。
示例2:
输入:root = [1,2,3,4,5,null,7]
输出:false
解释:值为 7 的结点没有尽可能靠向左侧。
思路:
由于完全二叉树的特点,除了最后一层,前面层的节点都是填满的,可以使用层序遍历,如果发现层有空节点,并且空节点之后又有不为空的节点,说明此时该层的数据不是满的
class Solution:
def isCompleteTree(self, root: TreeNode) -> bool:
if not root: return True
queue = [root]
# 标记是否有空节点
hasNone = False
while queue:
for i in range(len(queue)):
cur = queue.pop(0)
# 如果有空节点进行标记
if not cur:
hasNone=True
continue
# 如果已经标记有空节点,但是却发现还有新的不为空的节点,说明不是完全二叉树,返回False
if hasNone: return False
queue.append(cur.left)
queue.append(cur.right)
# 遍历完成后,说明是完全二叉树
return True