一、二叉树的最大深度
1.1 题目
给定一个二叉树 root
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
示例 1:
输入:root = [3,9,20,null,null,15,7] 输出:3
示例 2:
输入:root = [1,null,2] 输出:2
提示:
- 树中节点的数量在
[0, 10^4]
区间内。 -100 <= Node.val <= 100
1.2 题目链接
1.3 解题思路和过程想法
(1)解题思路:
1)递归高度:高度--从下往上高度递增----左右根----递归
# 递归的传入参数与返回值:“根”节点指针,树的高度。
# 递归出口:遇见空指针
# 主体:计算左子树的高度 l ,计算右子树的高度 r ,树的高度 = max(l,r) + 1
2)层序遍历:在层序遍历的过程中记录树的层数
(2)过程想法:
题目比较经典,思考过程比较自然。但是如果利用前序遍历的话,可能就有点复杂了,想等到学到回溯板块的时候再回来看看。
1.4 代码
1.4.1 递归高度
class Solution:
# 递归的传入参数与返回值:“根”节点指针,树的高度
def height(self,root) -> int:
# 递归出口:遇见空指针
if not root:
return 0
# 主体:计算左子树的高度 l ,计算右子树的高度 r ,树的高度 = max(l,r) + 1
l = self.height(root.left)
r = self.height(root.right)
root_height = max(l,r) + 1
return root_height
def maxDepth(self, root: Optional[TreeNode]) -> int:
# 高度--从下往上高度递增----左右根----递归
return self.height(root)
1.4.2 层序遍历
from queue import Queue
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
# 在层序遍历的过程中记录树的层数。
# 用来存储结果
res = 0
# 用来层序遍历的队列
myQueue = Queue()
# 层序遍历
if root:
myQueue.put(root)
while not myQueue.empty():
size = myQueue.qsize()
for i in range(size):
cur = myQueue.get()
if cur.left:
myQueue.put(cur.left)
if cur.right:
myQueue.put(cur.right)
# 更新树的层数
res += 1
return res
二、二叉树的最小深度
2.1 题目
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
说明:叶子节点是指没有子节点的节点。
示例 1:
输入:root = [3,9,20,null,null,15,7] 输出:2
示例 2:
输入:root = [2,null,3,null,4,null,5,null,6] 输出:5
提示:
- 树中节点数的范围在
[0, 10^5]
内 -1000 <= Node.val <= 1000
2.2 题目链接
2.3 解题思路和过程想法
(1)解题思路
1)后序遍历递归:区别于二叉树的最大深度
# 递归的传入参数:“根”节点指针,树的深度。
# 递归出口:遇见空指针
# 主体:计算左子树的高度 l ,计算右子树的高度 r ,根据数的情况求最小高度
2)层序遍历:在层序遍历的过程中记录树的层数,最早出现的叶节点的层数就是二叉树的最小深度。
(2)过程想法
题目比较经典,思考过程比较自然,但是在后序遍历的时候卡了一下,因为最小深度还是和最大深度有很大差别的。如果利用前序遍历的话,可能就有点复杂了,想等到学到回溯板块的时候再回来看看。
2.4 代码
2.4.1 递归高度
class Solution:
def minn(self,root) -> int:
if not root:
return 0
# 左
l = self.minn(root.left)
# 右
r = self.minn(root.right)
# 根
if root.left and not root.right:
res = l + 1
elif root.right and not root.left:
res = r + 1
else:
res = min(l,r) + 1
return res
def minDepth(self, root: Optional[TreeNode]) -> int:
# 总体思路:借助后序遍历递归,求左子树最小“深度”,求右子树最小“深度”,求根的最小“深度”
# 求根的最小深度不能直接写 res = min(l,r) + 1,因为若有一方为空,则会取到它的深度
# 但它实际不符合“叶子节点”的要求,故而需要分情况讨论
return self.minn(root)
2.4.2 层序遍历
from queue import Queue
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
# 在层序遍历的过程中记录树的层数,最早出现的叶节点的层数就是二叉树的最小深度
# 用来存储结果
res = 0
# 用来层序遍历的队列
myQueue = Queue()
# 层序遍历
if root:
myQueue.put(root)
while not myQueue.empty():
size = myQueue.qsize()
for i in range(size):
cur = myQueue.get()
# 记录叶子结点的层数
if not cur.left and not cur.right:
return res + 1
if cur.left:
myQueue.put(cur.left)
if cur.right:
myQueue.put(cur.right)
# 更新树的层数
res += 1
return res
三、完全二叉树的节点个数
3.1 题目
给你一棵 完全二叉树 的根节点 root
,求出该树的节点个数。
完全二叉树完全二叉树完全二叉树 的定义如下:在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h
层,则该层包含 1~ 2h
个节点。
示例 1:
输入:root = [1,2,3,4,5,6] 输出:6
示例 2:
输入:root = [] 输出:0
示例 3:
输入:root = [1] 输出:1
提示:
- 树中节点的数目范围是
[0, 5 * 10^4]
0 <= Node.val <= 5 * 10^4
- 题目数据保证输入的树是 完全二叉树
进阶:遍历树来统计节点是一种时间复杂度为 O(n)
的简单解决方案。你可以设计一个更快的算法吗?
3.2 题目链接
3.3 解题思路和过程想法
(1)解题思路
1)普通树-------后序遍历递归:
# 递归的传入参数与返回值:“根”节点指针,树的结点数
# 递归出口:遇见空指针
# 主体:计算左子树的结点数 l ,计算右子树的结点数 r ,树的高度 = l + r + 1
2)普通树--------层序遍历:
在层序遍历的过程中记录树的层数。
3)完全二叉树:
# 充分利用完全二叉树的性质以计算节点数量----满二叉树或最后一层叶子节点没有满
# n 层满二叉树的节点数为 2^n-1(完全二叉树是满二叉树的判断方式:向左递归的深度等于向右递归的深度)
# 充分利用此题中满二叉树的判断特性,不必遍历全部节点即可计算数的节点数
# 最后结合后序遍历递归计算整棵树的结点树
(2)过程想法
题目比较经典,普通树的节点计算方式是简单的,但本题特意强调了是完全二叉树,结合前者特性,才能使判断满二叉树变得简单(之前有思考要用完全二叉树的性质,但没想到这个思路)。
3.4 代码
3.4.1 后序遍历递归
class Solution:
def count(self,root) -> int:
if not root:
return 0
# 左
l = self.count(root.left)
# 右
r = self.count(root.right)
# 根
h = l + r + 1
return h
def countNodes(self, root: Optional[TreeNode]) -> int:
# 利用后序遍历递归:左右根
# 先计算左子树节点数,再计算右子树节点数,后计算总结点数
return self.count(root)
3.4.2 层序遍历
from queue import Queue
class Solution:
def countNodes(self, root: Optional[TreeNode]) -> int:
# 通过层序遍历,统计节点个数
# 用于层序遍历的队列
myQueue = Queue()
# 用于统计节点的变量
res = 0
# 层序遍历
if root:
myQueue.put(root)
while not myQueue.empty():
cur = myQueue.get()
# 统计节点数量
res += 1
if cur.left:
myQueue.put(cur.left)
if cur.right:
myQueue.put(cur.right)
return res
3.4.3 利用完全二叉树性质
class Solution:
def countNodes(self, root: Optional[TreeNode]) -> int:
# 充分利用完全二叉树的性质以计算节点数量----满二叉树或最后一层叶子节点没有满
# n 层满二叉树的节点数为 2^n-1(完全二叉树是满二叉树的判断方式:向左递归的深度等于向右递归的深度)
# 充分利用此题中满二叉树的判断特性,不必遍历全部节点即可计算数的节点数
# 最后结合后序遍历递归计算整棵树的结点树
# 递归出口
if not root:
return 0
# 记录左右子树的深度
leftDepth = 0
rightDepth = 0
# 初始化左右指针
left_p = root.left
right_p = root.right
# 向左递归,计算左侧深度
while left_p:
leftDepth += 1
left_p = left_p.left
# 向右递归,计算右侧深度
while right_p:
rightDepth += 1
right_p = right_p.right
# 如果左右侧深度相同,则是满二叉树,返回其节点个数
if leftDepth == rightDepth:
return (2 << leftDepth) -1
# 后序遍历--左右根
# 左
leftNodes = self.countNodes(root.left)
# 右
rightNodes = self.countNodes(root.right)
# 根
res = leftNodes + rightNodes + 1
return res