本篇基于b站灵茶山艾府的课上例题与课后作业。
104. 二叉树的最大深度
给定一个二叉树 root
,返回其最大深度。
二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:3
示例 2:
输入:root = [1,null,2]
输出:2
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def maxDepth(self, root: Optional[TreeNode]) -> int:
# 方法1:自底向上(归)
# def dfs(node):
# if node == None:
# return 0
# return max(dfs(node.left), dfs(node.right)) + 1
# return dfs(root)
# 方法2:自顶向下(递)
ans = 0
def dfs(node, cnt):
if node == None:
return
nonlocal ans
ans = max(ans, cnt)
dfs(node.left, cnt + 1)
dfs(node.right, cnt + 1)
dfs(root, 1)
return ans
111. 二叉树的最小深度
给定一个二叉树,找出其最小深度。
最小深度是从根节点到最近叶子节点的最短路径上的节点数量。
**说明:**叶子节点是指没有子节点的节点。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:2
示例 2:
输入:root = [2,null,3,null,4,null,5,null,6]
输出:5
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def minDepth(self, root: Optional[TreeNode]) -> int:
# # 最小深度是根节点到最近叶子节点的深度
# 1.自底向上(归)
# def dfs(node):
# # 递归边界
# if not node:
# return 0
# # 如果没有左孩子但是有右孩子,,说明当前不是叶子节点,还没有到递归边界,则变成右子树的最小深度的问题
# if not node.left:
# return dfs(node.right) + 1
# # 如果没有右孩子但是有左孩子,说明当前不是叶子节点,还没有到递归边界,变成左子树的最小深度的问题
# if not node.right:
# return dfs(node.left) + 1
# # 左右孩子都有,返回左子树的最小深度和右子树的最小深度加1
# return min(dfs(node.left), dfs(node.right)) + 1
# return dfs(root)
# 2.自顶向下(递)
def dfs(node, cnt):
nonlocal ans
if node == None:
return
# 最优性剪枝:继续向下递归也不会让最小深度变小
if cnt >= ans:
return
cnt += 1
# 如果是叶子节点,则记录答案,并返回
if not node.left and not node.right:
ans = min(ans, cnt)
return
# 如果不是叶子节点,则继续往下递归
dfs(node.left, cnt)
dfs(node.right, cnt)
ans = inf
dfs(root, 0)
return ans if ans != inf else 0
112. 路径总和
给你二叉树的根节点 root
和一个表示目标和的整数 targetSum
。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum
。如果存在,返回 true
;否则,返回 false
。
叶子节点 是指没有子节点的节点。
示例 1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
解释:等于目标和的根节点到叶节点路径如上图所示。
示例 2:
输入:root = [1,2,3], targetSum = 5
输出:false
解释:树中存在两条根节点到叶子节点的路径:
(1 --> 2): 和为 3
(1 --> 3): 和为 4
不存在 sum = 5 的根节点到叶子节点的路径。
示例 3:
输入:root = [], targetSum = 0
输出:false
解释:由于树是空的,所以不存在根节点到叶子节点的路径。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
def dfs(node, target):
# 边界条件是空节点,如果一个节点是空,则没有0,一定凑不到target
if not node:
return False
# 除空节点之外的节点可以分为非叶子节点和叶子节点
target -= node.val
# 如果是叶子节点
if node.left == node.right:
return target == 0
# 如果是非叶子节点,继续往下递归
return dfs(node.left, target) or dfs(node.right, target)
return dfs(root, targetSum)
129. 求根节点到叶节点数字之和
给你一个二叉树的根节点 root
,树中每个节点都存放有一个 0
到 9
之间的数字。
每条从根节点到叶节点的路径都代表一个数字:
- 例如,从根节点到叶节点的路径
1 -> 2 -> 3
表示数字123
。
计算从根节点到叶节点生成的 所有数字之和 。
叶节点 是指没有子节点的节点。
示例 1:
输入:root = [1,2,3]
输出:25
解释:
从根到叶子节点路径 1->2 代表数字 12
从根到叶子节点路径 1->3 代表数字 13
因此,数字总和 = 12 + 13 = 25
示例 2:
输入:root = [4,9,0,5,1]
输出:1026
解释:
从根到叶子节点路径 4->9->5 代表数字 495
从根到叶子节点路径 4->9->1 代表数字 491
从根到叶子节点路径 4->0 代表数字 40
因此,数字总和 = 495 + 491 + 40 = 1026
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def sumNumbers(self, root: Optional[TreeNode]) -> int:
# 1.有返回值写法
# def dfs(node, s):
# # 边界条件是节点为空时,不可能有值,返回
# if not node:
# return
# nonlocal ans
# # 非边界的节点可以分为叶子节点和非叶子节点
# s += str(node.val)
# # 如果是叶子节点,记录答案
# if node.left == node.right:
# ans += int(s)
# return
# # 如果是非叶子节点,继续递归
# dfs(node.left, s)
# dfs(node.right, s)
# ans = 0
# dfs(root, "")
# return ans
# 2.无返回值写法
def dfs(node, x):
if not node:
return 0
x = x * 10 + node.val
if node.left == node.right:
return x
return dfs(node.left, x) + dfs(node.right, x)
return dfs(root, 0)
1448. 统计二叉树中好节点的数目
给你一棵根为 root
的二叉树,请你返回二叉树中好节点的数目。
「好节点」X 定义为:从根到该节点 X 所经过的节点中,没有任何节点的值大于 X 的值。
示例 1:
输入:root = [3,1,4,3,null,1,5]
输出:4
解释:图中蓝色节点为好节点。
根节点 (3) 永远是个好节点。
节点 4 -> (3,4) 是路径中的最大值。
节点 5 -> (3,4,5) 是路径中的最大值。
节点 3 -> (3,1,3) 是路径中的最大值。
示例 2:
输入:root = [3,3,null,4,2]
输出:3
解释:节点 2 -> (3, 3, 2) 不是好节点,因为 "3" 比它大。
示例 3:
输入:root = [1]
输出:1
解释:根节点是好节点。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def goodNodes(self, root: Optional[TreeNode]) -> int:
# 1.向下递
# def dfs(node, mv): # mv表示max_val,根节点(第一个节点)到当前节点路径的最大节点值
# if not node:
# return
# nonlocal ans
# # 如果当前节点值大于等于路径上其他节点值,则是一个好节点
# if node.val >= mv:
# ans += 1
# mv = max(mv, node.val) # 更新这条路径上的最大节点值
# # 继续递归
# dfs(node.left, mv)
# dfs(node.right, mv)
# ans = 0
# dfs(root, -inf)
# return ans
# 2.向上归
def dfs(node, mv):
if not node:
return 0
mv = max(node.val, mv)
if node.val >= mv:
return dfs(node.left, mv) + dfs(node.right, mv) + 1
return dfs(node.left, mv) + dfs(node.right, mv)
return dfs(root, -inf)
987. 二叉树的垂序遍历
给你二叉树的根结点 root
,请你设计算法计算二叉树的 垂序遍历 序列。
对位于 (row, col)
的每个结点而言,其左右子结点分别位于 (row + 1, col - 1)
和 (row + 1, col + 1)
。树的根结点位于 (0, 0)
。
二叉树的 垂序遍历 从最左边的列开始直到最右边的列结束,按列索引每一列上的所有结点,形成一个按出现位置从上到下排序的有序列表。如果同行同列上有多个结点,则按结点的值从小到大进行排序。
返回二叉树的 垂序遍历 序列。
示例 1:
输入:root = [3,9,20,null,null,15,7]
输出:[[9],[3,15],[20],[7]]
解释:
列 -1 :只有结点 9 在此列中。
列 0 :只有结点 3 和 15 在此列中,按从上到下顺序。
列 1 :只有结点 20 在此列中。
列 2 :只有结点 7 在此列中。
示例 2:
输入:root = [1,2,3,4,5,6,7]
输出:[[4],[2],[1,5,6],[3],[7]]
解释:
列 -2 :只有结点 4 在此列中。
列 -1 :只有结点 2 在此列中。
列 0 :结点 1 、5 和 6 都在此列中。
1 在上面,所以它出现在前面。
5 和 6 位置都是 (2, 0) ,所以按值从小到大排序,5 在 6 的前面。
列 1 :只有结点 3 在此列中。
列 2 :只有结点 7 在此列中。
示例 3:
输入:root = [1,2,3,4,6,5,7]
输出:[[4],[2],[1,5,6],[3],[7]]
解释:
这个示例实际上与示例 2 完全相同,只是结点 5 和 6 在树中的位置发生了交换。
因为 5 和 6 的位置仍然相同,所以答案保持不变,仍然按值从小到大排序。
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def verticalTraversal(self, root: Optional[TreeNode]) -> List[List[int]]:
from collections import defaultdict
#哈希表,键为节点所在的列,值为(行,值)
li = defaultdict(list)
def dfs(root, i, j):
if root == None:
return
li[j].append((i, root.val))
dfs(root.left, i + 1, j - 1)
dfs(root.right, i + 1, j + 1)
dfs(root, 0, 0)
res = []
# sorted(li.items()):给哈希表中按键排序
for key, values in sorted(li.items()):
# 给值里面的列表排序,列表里面为元组,排序依据为元组的第一个值,再第二个值
values.sort()
res.append([i[1] for i in values])
return res