一、LeetCode513.找树左下角的值
1:题目描述(513. 找树左下角的值)
给定一个二叉树的 根节点 root
,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
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 findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
# 层序遍历
# queue = []
# result = []
# if not root:
# return None
# queue.append(root)
# while queue:
# q_len = len(queue)
# res = []
# while q_len:
# node = queue.pop(0)
# q_len -= 1
# res.append(node.val)
# if node.left:
# queue.append(node.left)
# if node.right:
# queue.append(node.right)
# result.append(res)
# return result[-1][0]
# 递归
maxpath = -float("INF") # 最大深度,初始为最小值
result = 0
def leftvalue(root, depth):
if root.left == None and root.right == None:
nonlocal maxpath, result
# 当遇到叶子节点时,判断当前深度与最大深度的值
if depth > maxpath:
maxpath = depth # 将当前深度赋值给最大深度
result = root.val # 并将此时叶子节点的值,复制给result
if root.left:
depth += 1 # 遍历节点的左节点,深度+1
leftvalue(root.left, depth)
depth -= 1 # 遍历节点的左节点结束后,深度需要-1,进行回溯
if root.right:
depth += 1
leftvalue(root.right, depth)
depth -= 1
return result
res = leftvalue(root, 0)
return res
二、LeetCode112. 路径总和
1:题目描述(112. 路径总和)
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。
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 hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
# # 递归
# # 将左右路径的节点值相加的和,添加到一个数组中,最后去判断targetSum是否存在数组中
# # res用来存储路径
# # res_sum用来存储每个路径的和
# def pathSum(root, res, res_sum):
# if root == None:
# return 0
# res.append(root.val) # 将节点添加到路径res中
# if root.left == None and root.right == None:
# # 若当前节点的左右子节点均为None,说明节点是叶子节点,已经到了路径的最后一个节点
# path_sum = sum(res) # 求路径的和
# res_sum.append(path_sum)
# return res_sum
# if root.left:
# pathSum(root.left, res, res_sum) # 遍历节点的左子树
# res.pop() # 回溯,将添加的节点,从路径中弹出,回到上一个节点
# if root.right:
# pathSum(root.right, res, res_sum)
# res.pop()
# return res_sum
# if not root:
# return False
# res = pathSum(root, [], [])
# if targetSum in res:
# return True
# else:
# return False
# 递归
def pathSum(cur, count):
if cur.left == None and cur.right == None and count == 0:
return True
if cur.left == None and cur.right == None and count != 0:
return False
if cur.left:
count -= cur.left.val
# 因为有返回值,所以需要有变量来承接返回值,返回值为True或False,可用来直接进行判断
# 如果返回的是True,则说明找到了一条符合要求的路径,需要将True一层一层的向上返回
# 所以为True时,向上返回True
if pathSum(cur.left, count): return True
# 回溯,需要返回到上一个节点
count += cur.left.val
if cur.right:
count -= cur.right.val
if pathSum(cur.right, count): return True
count += cur.right.val
# 如果一直都没有True返回,则说明不存在一条符合要求的路径,返回False
return False
if not root:
return False
res = pathSum(root, targetSum-root.val)
return res
三、LeetCode113.路径总和ii
1:题目描述(113. 路径总和 II)
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
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 pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
# 递归
# import copy
# def path(root, res, result):
# res.append(root.val)
# if root.left == None and root.right == None:
# # 节点的左右子节点为None,说明是叶子节点,已经到了路径的最后一个节点
# # 不能直接将res加入result中,因为res是在变的,使用深copy将res赋值给l
# l = copy.deepcopy(res)
# result.append(l)
# return result
# if root.left:
# path(root.left, res, result)
# # 回溯,遍历完一条路径后,回到当前节点的父节点
# res.pop()
# if root.right:
# path(root.right, res, result)
# # 回溯,遍历完一条路径后,回到当前节点的父节点
# res.pop()
# return result
# result_list = []
# if not root:
# return result_list
# res_list = path(root, [], [])
# for i in range(len(res_list)):
# if targetSum == sum(res_list[i]):
# result_list.append(res_list[i])
# return result_list
# 递归
def hasPath(cur, remain):
if cur.left == None and cur.right == None and remain == 0:
# 节点的左右子节点为None,并且路径的总值等于目标值了,说明找到了符合要求的路径
# 将路径添加到resul中
result.append(path[:])
elif cur.left == None and cur.right == None and remain != 0:
# 到了叶子节点,路径的总值与目标值的差值不为0,说明路径不满足要求,返回上层
return
if cur.left:
# 将左节点加入path路径中
path.append(cur.left.val)
# 减去左节点的值
remain -= cur.left.val
hasPath(cur.left, remain)
# 回溯
remain += cur.left.val
path.pop()
if cur.right:
path.append(cur.right.val)
remain -= cur.right.val
hasPath(cur.right, remain)
remain += cur.right.val
path.pop()
return result
result = []
path = []
if not root:
return []
path.append(root.val)
hasPath(root, targetSum-root.val)
return result
四、LeetCode106.从中序与后序遍历序列构造二叉树
1:题目描述(106. 从中序与后序遍历序列构造二叉树)
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
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 buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
# 第一步:特殊情况:数为空,或递归终止条件
if not postorder:
return None
# 第二步:后序遍历的最后一个就是当前的中间节点
root_val = postorder[-1]
root = TreeNode(root_val) # 定义一个新节点
# 第三步:找切割点,在中序遍历中寻找切割点
separator_idx = inorder.index(root_val)
# 第四步:切割inorder数组,得到inorder数组的左、右半边
# 中历序遍的顺序为:左、中、右
# 左半边为左子树,右半边为右子树
inorder_left = inorder[:separator_idx]
inorder_right = inorder[separator_idx+1:]
# 第五步:切割postorder数组,得到postorder数组的左、右半边
# 中序数组大小一定是跟后序数组大小相同的
# 后历序遍的顺序为:左、右、中
# 左半边为左子树,右半边为右子树
postorder_left = postorder[:len(inorder_left)]
postorder_right = postorder[len(inorder_left):len(postorder)-1]
# 第六步:递归-单层递归逻辑
root.left = self.buildTree(inorder_left, postorder_left)
root.right = self.buildTree(inorder_right, postorder_right)
return root
五、LeetCode105.从前序与中序遍历序列构造二叉树
1:题目描述(105. 从前序与中序遍历序列构造二叉树)
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
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 buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
# 第一步:特殊情况:树为空(递归终止条件)
if not preorder:
return None
# 第二步:确定中间节点,前序遍历的第一个节点是当前的中间节点
root_val = preorder[0]
root = TreeNode(root_val)
# 第三步:找切割点,在中序遍历中寻找切割点
separator_idx = inorder.index(root_val)
# 第四步:切割中序数组,分割左右子树
inorder_left = inorder[:separator_idx]
inorder_right = inorder[separator_idx+1:]
# 第五步:切割前序数组,分割左右子树
# 前序数组的长度与中序数组的长度一定相等
preorder_left = preorder[1:1+len(inorder_left)]
preorder_right = preorder[1+len(inorder_left):]
# 第六步:递归
root.left = self.buildTree(preorder_left, inorder_left)
root.right = self.buildTree(preorder_right, inorder_right)
return root