题目链接:513. 找树左下角的值 - 力扣(Leetcode)112. 路径总和 - 力扣(Leetcode)106. 从中序与后序遍历序列构造二叉树 - 力扣(Leetcode)
513 找树左下角的值
给定一个二叉树的 根节点 root
,请找出该二叉树的 最底层 最左边 节点的值。
假设二叉树中至少有一个节点。
输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7
疑问:
1. 怎么识别层数
可以看深度,深度最大的叶子节点即为结果
2. 怎么登记好左右子节点的深度/高度
要点:
1. 记录每个点的深度
2. 找出深度最大的最左侧的叶子结点
参考代码——递归
class Solution:
def findBottomLeftValue(self, root: TreeNode) -> int:
max_depth = -float("INF")
leftmost_val = 0
def __traverse(root, cur_depth):
nonlocal max_depth, leftmost_val
if not root.left and not root.right:
if cur_depth > max_depth:
max_depth = cur_depth
leftmost_val = root.val
if root.left:
cur_depth += 1
__traverse(root.left, cur_depth)
cur_depth -= 1 #回溯
if root.right:
cur_depth += 1
__traverse(root.right, cur_depth)
cur_depth -= 1
__traverse(root, 0)
return leftmost_val
注意:
1. 如果不在_traversal中加入参数cur_depth,直接在开头设cur_depth为0或1,每次递归的时候就会重置cur_depth
2. 遍历完左或右叶子节点后,更新最大深度,然后回溯到其中间节点,因此cur_depth要紧跟着-1。
自写
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
result =None
max_depth = 0
def get_depth(root,root_depth) -> int:#前序遍历
nonlocal max_depth, result
if not root.left and not root.right:
if root_depth > max_depth:
max_depth = root_depth
result = root.val
if root.left:
root_depth += 1
get_depth(root.left,root_depth)
root_depth -= 1
if root.right:
root_depth += 1
get_depth(root.right, root_depth)
root_depth -= 1
get_depth(root,0)
return result
无法通过root = [0]这个用例,结果返回null。原因?
112 路径总和
给你二叉树的根节点 root
和一个表示目标和的整数 targetSum
。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum
。如果存在,返回 true
;否则,返回 false
。
叶子节点 是指没有子节点的节点。
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22 输出:true 解释:等于目标和的根节点到叶节点路径如上图所示。
自写
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
sum = 0
def _traversal(root):
if not root.left and not root.right:
sum += root.val
if sum == targetSum:
return True
if root.left:
sum += root.val
if _traversal(root.left): return True
sum -= root.val
if root.right:
sum += root.val
if _traversal(root.right):return True
sum -= root.val
return False
疑问:为什么不能用相加的方式,必须用减?
参考代码
class solution:
def haspathsum(self, root: treenode, targetsum: int) -> bool:
def isornot(root, targetsum) -> bool:
if (not root.left) and (not root.right) and targetsum == 0:
return true # 遇到叶子节点,并且计数为0
if (not root.left) and (not root.right):
return false # 遇到叶子节点,计数不为0
if root.left:
targetsum -= root.left.val # 左节点
if isornot(root.left, targetsum): return true # 递归,处理左节点
targetsum += root.left.val # 回溯
if root.right:
targetsum -= root.right.val # 右节点
if isornot(root.right, targetsum): return true # 递归,处理右节点
targetsum += root.right.val # 回溯
return false
if root == none:
return false # 别忘记处理空treenode
else:
return isornot(root, targetsum - root.val)
106 从中序与后序遍历序列构造二叉树
给定两个整数数组 inorder
和 postorder
,其中 inorder
是二叉树的中序遍历, postorder
是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3] 输出:[3,9,20,null,null,15,7]
基本思路:通过后序队列中的最后一个元素(根节点)去切割中序队列,以根节点元素为界切成左右子区间,再在右区间内继续通过找后序队列中右区间的最后元素来切割左右区间,以此递归。
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组
第六步:递归处理左区间和右区间
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> 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数组的左,右半边.
# 重点1: 中序数组大小一定跟后序数组大小是相同的.
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