这篇可以主要关注一下如何确定递归时是否需要返回值。
LC513. 找树左下角的值
给定一个二叉树的根节点,请找出该二叉树的 最底层最左边 节点的值。
思路1 层序遍历
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
if not root: return -1
# leverOrder
from collections import deque
que = deque()
que.append(root)
while que:
size = len(que)
for i in range(size):
node = que.popleft()
if i == 0:
ans = node.val
if node.left: que.append(node.left)
if node.right: que.append(node.right)
return ans
思路2 深度优先方法要困难一些,递归判断结点是否是深度最大的叶子结点,只遍历,没有进行什么操作,所以不需要有返回值。这种写法是隐含了回溯的,不需要自己写,因为函数调用完形参就释放了。
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
def isleaf(root):
return root and not root.left and not root.right
# 深度优先
max_depth = 0
target = root.val
def dfs(root, depth):
nonlocal max_depth, target
if not root: return
depth += 1
if isleaf(root):
if depth > max_depth:
max_depth = depth
target = root.val
dfs(root.left, depth)
dfs(root.right, depth)
dfs(root, 0)
return target
下面这种写法是把回溯写出来了,因为depth一直在变的。
class Solution:
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
def isleaf(root):
return root and not root.left and not root.right
leftval = root.val
max_d = 0
depth = 0
def dfs(root):
nonlocal leftval, max_d, depth
if not root: return
depth += 1
if isleaf(root):
if depth > max_d:
max_d = depth
leftval = root.val
if root.left:
dfs(root.left)
depth -= 1
if root.right:
dfs(root.right)
depth -= 1
dfs(root)
return leftval
LC112. 路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false。
下面是我自己的写法,虽然AC了(其中要注意ans写成nonlocal),但是问题是找到了目标路径和之后还是会进行一整个树的遍历。
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
def isleaf(root):
return root and not root.left and not root.right
# 先序遍历
ans = False
pathsum = 0
def dfs(root, pathsum):
nonlocal ans
if not root: return
pathsum += root.val
if isleaf(root):
if pathsum == targetSum:
ans = True
if root.left: dfs(root.left, pathsum)
if root.right: dfs(root.right, pathsum)
dfs(root,pathsum)
return ans
本题搜索出一条符合条件的路径即可,所以递归一定要有返回值,遇到符合的路径要及时返回。下面的写法好多了。
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
def isleaf(root):
return root and not root.left and not root.right
# 先序遍历
def dfs(root, pathsum) -> bool:
pathsum += root.val
# 叶子结点如果找到了路径和,True;否则False
if isleaf(root):
if pathsum == targetSum:
return True
else:
return False
# 如果左孩子里面找到了路径和,返回True
if root.left:
if dfs(root.left, pathsum):
return True
# 如果右孩子里面找到了路径和,返回True
if root.right:
if dfs(root.right, pathsum):
return True
# 都没有找到,返回False
return False
if not root: return False #这一行也重要
return dfs(root,0)
LC113. 路径总和 II
给你二叉树的根节点 root
和一个整数目标和 targetSum
,找出所有从根节点到叶子节点路径总和等于给定目标和的路径。
本题是需要遍历完整棵树,且不用处理递归返回值,就不需要返回值。
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
def isleaf(root):
return root and not root.left and not root.right
paths = []
path = []
def dfs(root, sum_pre):
if not root: return
path.append(root.val)
sum_pre += root.val
# print(sum_pre, path)
if isleaf(root) and sum_pre == targetSum: #写的时候isleaf后面的(root)也忘了写,就变成了是否存在isleaf函数,就一直都是True。多花了时间调试,写的时候就要慢慢细致地写。
paths.append(path[:]) #[:]不要忘了加
if root.left:
dfs(root.left, sum_pre)
path.pop()
if root.right:
dfs(root.right, sum_pre)
path.pop()
dfs(root, 0)
return paths
LC106. 从中序与后序遍历序列构造二叉树
这题没有看答案一次AC了,大晚上的开心了好一会儿~这草稿也是只有自己能看懂了LOL。
本题需要遍历完整棵树,但需要对递归返回值(结点)进行处理(链接),所以需要有返回值。
# 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 find(self, nums, val):
for i, num in enumerate(nums):
if num == val:
return i
return -1
def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]:
# def constructTree(inorder, postorder: List[int]) -> Optional[TreeNode]:
if not inorder: return None
if len(inorder) == 1: return TreeNode(inorder[0])
m = postorder[-1]
node = TreeNode(m)
i = self.find(inorder, m)
print(m,i)
l_inorder = inorder[0:i]
r_inorder = inorder[i+1:]
l_postorder = postorder[0:i]
r_postorder = postorder[i:-1]
node.left = self.buildTree(l_inorder,l_postorder)
node.right = self.buildTree(r_inorder,r_postorder)
return node
LC105. 从前序与中序遍历序列构造二叉树
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
和上题一样的写法,但写find函数时出现了小问题,要在循环结束时还没return才返回-1。
class Solution:
def find(self, nums, val):
for i, num in enumerate(nums):
if num == val:
return i
return -1
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
if not preorder: return None
Node = TreeNode(preorder[0])
mid = preorder[0]
i = self.find(inorder, mid)
l_inorder, r_inorder = inorder[0:i], inorder[i+1:]
l_preorder, r_preorder = preorder[1:i+1], preorder[i+1:]
Node.left = self.buildTree(l_preorder, l_inorder)
Node.right = self.buildTree(r_preorder, r_inorder)
return Node
看了答案之后发现在list中查找元素的时候,不需要自己写函数,用自身的index方法,直接i = inorder.index(mid)即可。
明天加油~
参考资料:路径总和-代码随想录