相关推荐
python coding with ChatGPT 打卡第12天| 二叉树:理论基础
python coding with ChatGPT 打卡第13天| 二叉树的深度优先遍历
python coding with ChatGPT 打卡第14天| 二叉树的广度优先遍历
python coding with ChatGPT 打卡第15天| 二叉树:翻转二叉树、对称二叉树
文章目录
- 完全二叉树的节点个数
- Key Points
- 相关题目
- 视频讲解
- 重点分析
- 平衡二叉树
- Key Points
- 相关题目
- 视频讲解
- 重点分析
- 拓展
- 二叉树的所有路径
- 相关题目
- 视频讲解
- 重点分析
- 左叶子之和
- Key Points
- 相关题目
- 视频讲解
- 重点分析
完全二叉树的节点个数
Key Points
- 利用完全二叉树的性质:完全二叉树是一种特殊的二叉树,除了最底层,其它每一层都被完全填满,而且最底层从左到右填入节点。
相关题目
222. 完全二叉树的节点个数
视频讲解
理解普通二叉树和完全二叉树的区别
重点分析
首先,我们来思考一下如何递归地解决这个问题,再考虑是否有更高效的方法。
方法一:
def countNodes(root):
if not root:
return 0
count_left = countNodes(root.left)
count_right = countNodes(root.right)
return count_left + count_right + 1
方法二:(迭代法遍历节点)
def countNodes(root):
if not root:
return 0
stack_record = [root]
count = 0
while stack_record:
node = stack_record.pop()
count += 1
if node.right:
stack_record.append(node.right)
if node.left:
stack_record.append(node.left)
return count
解决这个问题的关键是利用完全二叉树的性质。
完全二叉树的高度可以通过连续地访问左子树
来确定。
方法三:
如果左子树的高度等于右子树的高度,则为满二叉树
def get_height(node):
if not node:
return 0
height = 0
while node:
node = node.left
height += 1
return height
def get_count(height):
num = 2**height - 1
return num
def countNodes(root):
if not root:
return 0
left_height = get_height(root.left)
right_height = get_height(root.right)
if left_height > right_height:
right_count = get_count(right_height)
left_count = countNodes(root.left)
else:
left_count = get_count(left_height)
right_count = countNodes(root.right)
return 1+left_count+right_count
方法四:
在完全二叉树中,如果递归向左遍历的深度等于递归向右遍历的深度,那说明就是满二叉树。
def countNodes(root):
if not root:
return 0
left = root.left
right = root.right
left_height = 1
right_height = 1
while left:
left_height += 1
left = left.left
while right:
right_height += 1
right = right.right
if left_height == right_height:
return get_count(left_height)
return countNodes(root.left) + countNodes(root.right) + 1
class Solution: # 利用完全二叉树特性
def countNodes(self, root: TreeNode) -> int:
if not root: return 0
count = 1
left = root.left; right = root.right
while left and right:
count += 1
left = left.left; right = right.right
if not left and not right: # 如果同时到底说明是满二叉树,反之则不是
return 2**count-1
return 1 + self.countNodes(root.left) + self.countNodes(root.right)
平衡二叉树
Key Points
判断一个二叉树是否是高度平衡的,其定义是:一个二叉树每个节点的左右两个子树的高度差的绝对值不超过1,并且左右两个子树都是高度平衡的二叉树。
相关题目
110. 平衡二叉树
视频讲解
后序遍历求高度
重点分析
def isBalanced(root):
if not root:
return True
height = get_height(root)
if height == -1:
return False
return True
def get_height(node):
if not node:
return 0
left_height = get_height(node.left)
right_height = get_height(node.right)
if left_height == -1 or right_height == -1:
return -1
if abs(left_height - right_height) > 1:
return -1
return 1 + max(left_height, right_height)
这种方法的好处是它在计算高度的同时检查平衡性
,只需遍历树一次,提高了效率。
拓展
二叉树的所有路径
相关题目
257. 二叉树的所有路径
视频讲解
递归中带着回溯
重点分析
方法一:
递归法
class Solution:
def binaryTreePaths(self, root: TreeNode) -> [str]:
if not root:
return []
paths = []
self._findPaths(root, "", paths)
return paths
def _findPaths(self, node, path, paths):
# 更新当前路径
currentPath = path + str(node.val)
# 如果是叶子节点,添加路径到结果列表
if not node.left and not node.right:
paths.append(currentPath)
else:
# 如果不是叶子节点,递归遍历子节点
if node.left:
self._findPaths(node.left, currentPath + "->", paths)
if node.right:
self._findPaths(node.right, currentPath + "->", paths)
# 示例使用
# 假设我们有一个二叉树,我们可以创建这个树的节点,并调用上述函数
# 比如:
# 1
# / \
# 2 3
# \
# 5
# root = TreeNode(1)
# root.left = TreeNode(2)
# root.right = TreeNode(3)
# root.left.right = TreeNode(5)
# solution = Solution()
# print(solution.binaryTreePaths(root))
方法二:
迭代法(更好理解)
class Solution:
def binaryTreePaths(self, root: TreeNode) -> [str]:
if not root:
return []
paths = []
stack = [(root, str(root.val))] # 初始化栈,包含节点和路径
while stack:
node, path = stack.pop() # 取出当前节点和路径
# 如果是叶子节点,添加路径到结果列表
if not node.left and not node.right:
paths.append(path)
else:
# 如果不是叶子节点,更新路径并将子节点加入栈
if node.right:
stack.append((node.right, path + "->" + str(node.right.val)))
if node.left:
stack.append((node.left, path + "->" + str(node.left.val)))
return paths
在这个迭代版本中,我们使用了一个栈来存储每个节点以及从根节点到该节点的路径。这种方法模拟了递归过程的深度优先搜索(DFS)前序遍历,确保了我们能够访问到每一个叶子节点,并在到达叶子节点时记录完整的路径。
这种迭代方法提供了一种不使用系统调用栈的递归的替代方案,对于深度非常大的树来说,可以避免递归导致的栈溢出问题。
左叶子之和
Key Points
- 要注意是判断左叶子,不是二叉树左侧节点
- 判断是否是左叶子,需要通过父节点来判断
相关题目
404. 左叶子之和
视频讲解
总有一些规则让你找不到北
重点分析
方法一:
递归法:
def sumOfLeftLeaves(root):
if not root:
return 0
res = 0
if isLeave(root.left):
res += root.left.val
res += sumOfLeftLeaves(root.right)
else:
res += sumOfLeftLeaves(root.left) + sumOfLeftLeaves(root.right)
return res
def isLeave(node):
if node:
if not node.left and not node.right:
return True
return False
方法二:
迭代法(更好理解)
def sumOfLeftLeaves(root):
if not root:
return 0
stack_record = [root]
res = 0
while stack_record:
node = stack_record.pop()
if isLeave(node.left):
res += node.left.val
if node.right:
stack_record.append(node.right)
else:
if node.right:
stack_record.append(node.right)
if node.left:
stack_record.append(node.left)
return res
精简版:
def sumOfLeftLeaves(root):
if not root:
return 0
stack_record = [root]
res = 0
while stack_record:
node = stack_record.pop()
if isLeave(node.left):
res += node.left.val
if node.right:
stack_record.append(node.right)
if node.left:
stack_record.append(node.left)
return res