Day 16
二叉树各种遍历的应用
回溯
513. 找树左下角的值
给定一个二叉树的根节点root,请找出该二叉树的最底层最左边节点的值。假设二叉树中至少有一个节点。
解:回溯(递归)或层序遍历
# 递归法
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
maxDepth = -1
result = 0
if root == None:
return 0
def findMax(root, depth):
nonlocal maxDepth, result # 使用函数外定义的变量
if not root.left and not root.right:
if depth > maxDepth: # 更新最大深度和最左叶子节点
maxDepth = depth
result = root.val
if root.left:
depth += 1
findMax(root.left, depth)
depth -= 1 # 要回溯,也就是回到上一层继续查找,所以层数要-1
if root.right:
depth += 1
findMax(root.right, depth)
depth -= 1 # 要回溯
return
findMax(root, 0)
return result
# 迭代
from collections import deque
class Solution:
def findBottomLeftValue(self, root: TreeNode) -> int:
queue = deque()
if root:
queue.append(root)
result = 0
while queue:
q_len = len(queue)
for i in range(q_len):
if i == 0:
result = queue[i].val
cur = queue.popleft()
if cur.left:
queue.append(cur.left)
if cur.right:
queue.append(cur.right)
return result
112. 路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
解:递归函数什么时候需要返回值?什么时候不需要返回值?总结为如下三点:
- 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。
- 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。
- 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
如题,只需要求其中一条路,就需要返回值,而后面的113题需要求路径,要遍历整棵树,就不需要返回值。
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if root == None:
return False
def countSum(root, count):
if root.left == None and root.right == None:
if count == 0:
return True
else:
return False
if root.left:
# 隐藏回溯写法,因为传入的是count-val,count不变,所以回溯被省略了
if countSum(root.left, count-root.left.val):
return True
if root.right:
# 回溯写法
count -= root.right.val
if countSum(root.right, count):
return True
count += root.right.val
return False
return countSum(root, targetSum-root.val)
113. 路径总和 II(中等)
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
解:如上题所说,需要遍历整棵树并找出所有路径。
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
result = []
path = []
if not root:
return result
def findPath(root, count):
if root.left == None and root.right == None:
if count == 0:
result.append(path[:]) # 要加个[:]否则result和path共内存,pop后会改变result
else:
return
if root.left:
path.append(root.left.val)
findPath(root.left, count - root.left.val)
path.pop()
if root.right:
path.append(root.right.val)
findPath(root.right, count - root.right.val)
path.pop()
return path
path.append(root.val)
findPath(root, targetSum - root.val)
return result
遍历确定二叉树
106. 从中序与后序遍历序列构造二叉树
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗二叉树。
解:如何根据遍历进行求解呢?中序遍历是[左侧树],根,[右侧树],后序遍历是[左侧树],[右侧树],根,因此后序的最后一个点为根,找到中序中的根,即可找出左侧树和右侧树。再在后序中找到左侧树和右侧树的根,以此类推。
这种一层一层切割的方法,适合用递归。具体分为以下几步:
第一步:如果数组大小为零的话,说明是空节点了。
第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
第五步:切割后序数组,切成后序左数组和后序右数组
第六步:递归处理左区间和右区间
class Solution:
def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
# 1.判断空节点
if not postorder:
return
# 2.后序数组最后一个是节点
node_val = postorder[-1]
node = TreeNode(node_val)
# 3.以节点切割中序数组
node_index = inorder.index(node_val)
# 4.切割中序数组
left_inorder = inorder[:node_index]
right_inorder = inorder[node_index+1:]
# 5.切割后序数组
length = len(left_inorder)
left_postorder = postorder[:length]
right_postorder = postorder[length:-1]
# 6.递归
node.left = self.buildTree(left_inorder,left_postorder)
node.right = self.buildTree(right_inorder,right_postorder)
return node
105. 从前序与中序遍历序列构造二叉树
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
解:类似的
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
# 1.判断空节点
if not preorder:
return
# 2.先序数组第一个是节点
node_val = preorder[0]
node = TreeNode(node_val)
# 3.以节点切割中序数组
node_index = inorder.index(node_val)
# 4.切割中序数组
left_inorder = inorder[:node_index]
right_inorder = inorder[node_index+1:]
# 5.切割先序数组
length = len(left_inorder)
left_preorder = preorder[1:length+1]
right_preorder = preorder[length+1:]
# 6.递归
node.left = self.buildTree(left_preorder,left_inorder)
node.right = self.buildTree(right_preorder,right_inorder,)
return node