找树左下角的值
- 本题递归偏难,反而迭代简单属于模板题, 两种方法掌握一下
- 层序遍历
- 如何判断是最后一行呢,其实就是深度最大的叶子节点一定是最后一行。
- 如何找最左边的呢?可以使用前序遍历(当然中序,后序都可以,因为本题没有 中间节点的处理逻辑,只要左优先就行),保证优先左边搜索,然后记录深度最大的叶子节点,此时就是树的最后一行最左边的值。
if root is None:
return 0
queue = deque()
queue.append(root)
result = 0
while queue:
size = len(queue)
for i in range(size):
node = queue.popleft()
if i == 0:
result = node.val
if node.left:
queue.append(node.left)
if node.right:
queue.append(node.right)
return result
递归和回溯:
class Solution:
def findBottomLeftValue(self, root: TreeNode) -> int:
self.max_depth = float('-inf')
self.result = None
self.traversal(root, 0)
return self.result
def traversal(self, node, depth):
if not node.left and not node.right:
if depth > self.max_depth:
self.max_depth = depth
self.result = node.val
return
if node.left:
depth += 1
self.traversal(node.left, depth)
depth -= 1
if node.right:
depth += 1
self.traversal(node.right, depth)
depth -= 1
112. 路径总和
- 涉及到回溯的过程,而且回溯的过程隐藏的还挺深
-
- 路径总和,和 113. 路径总和ii 一起做了。 优先掌握递归法。
思路:
- 路径总和,和 113. 路径总和ii 一起做了。 优先掌握递归法。
- 递归函数什么时候要有返回值,什么时候没有返回值,特别是有的时候递归函数返回类型为bool类型。这里总结如下三点:
-
- 如果需要搜索整棵二叉树且不用处理递归返回值,递归函数就不要返回值。(这种情况就是本文下半部分介绍的113.路径总和ii)
-
- 如果需要搜索整棵二叉树且需要处理递归返回值,递归函数就需要返回值。 (这种情况我们在236. 二叉树的最近公共祖先 (opens new window)中介绍)
-
- 如果要搜索其中一条符合条件的路径,那么递归一定需要返回值,因为遇到符合条件的路径了就要及时返回。(本题的情况)
class Solution:
def traversal(self, cur: TreeNode, count: int) -> bool:
if not cur.left and not cur.right and count == 0: # 遇到叶子节点,并且计数为0
return True
if not cur.left and not cur.right: # 遇到叶子节点直接返回
return False
if cur.left: # 左
count -= cur.left.val
if self.traversal(cur.left, count): # 递归,处理节点
return True
count += cur.left.val # 回溯,撤销处理结果
if cur.right: # 右
count -= cur.right.val
if self.traversal(cur.right, count): # 递归,处理节点
return True
count += cur.right.val # 回溯,撤销处理结果
return False
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if root is None:
return False
return self.traversal(root, sum - root.val)
113. 路径总和
class Solution:
def traversal(self,cur,target,path,res):
if not cur.left and not cur.right and target==0:
res.append(path[:])
return
if not cur.left and not cur.right:
return []
if cur.left:
path.append(cur.left.val)
self.traversal(cur.left, target - cur.left.val, path, res)
path.pop()
if cur.right:
path.append(cur.right.val)
self.traversal(cur.right,target-cur.right.val,path,res)
path.pop()
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
path=[]
res=[]
if not root:
return res
path.append(root.val)
self.traversal(root,targetSum-root.val,path,res)
return res
106. 从中序与后序遍历序列构造二叉树
- 106.从中序与后序遍历序列构造二叉树,105.从前序与中序遍历序列构造二叉树 一起做,思路一样的
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)
# 第三步: 找切割点.
sep_idx=inorder.index(root_val)
# 第四步: 切割inorder数组. 得到inorder数组的左,右半边.
inorder_left=inorder[:sep_idx]
inorder_right=inorder[sep_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
105.从前序与中序遍历序列构造二叉树
class Solution:
def buildTree(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]:
# 前序遍历:中左右
# 中序遍历:左中右
if not preorder:
return None
root_val=preorder[0]#3
root=TreeNode(root_val)#构建根节点
# 切割点
inorder_sep=inorder.index(root_val)#1
#中序的左右数组
inorder_left=inorder[:inorder_sep]#9
inorder_right=inorder[inorder_sep+1:]#15,20,7
#前序的左右数组
preorder_left=preorder[1:len(inorder_left)+1]#9
preorder_right=preorder[1+len(inorder_left):]#20,15,7
# 迭代
root.left=self.buildTree(preorder_left,inorder_left)
root.right=self.buildTree(preorder_right,inorder_right)
return root