LeetCode 513 找树左下角的值
题目链接:513. 找树左下角的值 - 力扣(Leetcode)
确实乍一看题目很容易想到用二叉树的层序遍历就能解决问题:
# 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:
# 层序遍历
q = collections.deque()
q.append(root)
res = 0
while q:
n = len(q)
for i in range(n):
cur = q.popleft()
if i == 0:
res = cur.val
if cur.left:
q.append(cur.left)
if cur.right:
q.append(cur.right)
return res
而递归思路的难点在于如何找到最后一行。这时需要借助树的深度,深度最大的叶节点位于最后一层,按从左到右的顺序遍历就可以优先找到该行的第一个叶节点。
# 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 __init__(self):
self.maxdepth = -1
self.result = 0
def findBottomLeftValue(self, root: Optional[TreeNode]) -> int:
# 递归
def dfs(node, depth):
if not node.left and not node.right:
# 只要深度大于原最大深度才会更新和获得节点值
# (等于时也不会进入if语句,因此能保证result获得的都是每一层的最左边叶节点值)
if depth > self.maxdepth:
self.maxdepth = depth
self.result = node.val
return
if node.left:
dfs(node.left, depth + 1)
if node.right:
dfs(node.right, depth + 1)
return
dfs(root, 0)
return self.result
实现时在Python类中实现了__init__函数,初始化全局变量,若递归时深度从0开始,最大深度的初始值就不能设为0,否则root为叶节点时就会出错。
LeetCode 112 路径总和
这题路径总和只需要找到其中一条满足条件的路径即可,在深度优先遍历递归过程中传入当前节点和剩余总和值curSum(targetSum-前面已遍历节点的值之和),遇到叶子节点时就能判断curSum和当前节点值是否相等。和讲解实现的差异是这里dfs初始时传入的是targetSum,默认传入dfs的node还没有遍历到,而讲解中初始时传入的是targetSum-root.val,所以会在叶节点处判断curSum是否等于0。
# 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:
if not root:
return False
def dfs(node, curSum):
# 节点值可以为负数,不能这样剪枝
# if curSum < 0:
# return False
# 遇到叶节点
if not node.left and not node.right:
return True if curSum == node.val else False
res = False
if node.left:
left = dfs(node.left, curSum - node.val)
res = res or left
if node.right:
right = dfs(node.right, curSum - node.val)
res = res or right
return res
result = dfs(root, targetSum)
return result
实现时要注意细节,开始时下意识加了和为负数的剪枝,但题目的节点值可以为负数,和也可以是负数,这种情况下就不能做剪枝。
LeetCode 113 路径总和II
题目链接: 113. 路径总和 II - 力扣(Leetcode)
本题和路径总和思路相同,只需要把叶节点处返回bool值的逻辑修改为收集结果,并且在左右子树的递归逻辑前后加入路径的添加和回溯:
# 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]]:
if not root:
return []
result, path = [], []
def dfs(node, curSum):
# 遇到叶节点
if not node.left and not node.right:
if curSum == node.val:
result.append(path[:] + [node.val])
if node.left:
path.append(node.val)
dfs(node.left, curSum - node.val)
path.pop()
if node.right:
path.append(node.val)
dfs(node.right, curSum - node.val)
path.pop()
dfs(root, targetSum)
return result
LeetCode 106 从中序与后序遍历序列构造二叉树
题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(Leetcode)
# 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]:
def build(pre_left, pre_right, in_left, in_right):
# 用下标标记数组的区间,左闭右开
if pre_right <= pre_left:
return None
root = TreeNode(val=preorder[pre_left])
in_idx = inorder.index(preorder[pre_left]) # 根节点在inorder中的下标
len_left = in_idx - in_left # 左子树的节点数
root.left = build(pre_left+1, pre_left+1+len_left, in_left, in_idx)
root.right = build(pre_left+1+len_left, pre_right, in_idx+1, in_right)
return root
n = len(preorder) # 节点总数
root = build(0, n, 0, n)
return root
LeetCode 105 从前序与中序遍历序列构造二叉树
题目链接:106. 从中序与后序遍历序列构造二叉树 - 力扣(Leetcode)
# 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]:
def build(post_left, post_right, in_left, in_right):
# 用下标标记数组的区间,左闭右开
if post_right <= post_left:
return None
root = TreeNode(val=postorder[post_right-1])
in_idx = inorder.index(postorder[post_right-1]) # 根节点在inorder中的下标
len_left = in_idx - in_left # 左子树的节点数
root.left = build(post_left, post_left+len_left, in_left, in_idx)
root.right = build(post_left+len_left, post_right-1, in_idx+1, in_right)
return root
n = len(postorder) # 节点总数
root = build(0, n, 0, n)
return root
106和105的构造二叉树不难,只要理解如何根据前序或后序数组,递归划分两个遍历序列即可。实现时会稍微繁琐一些,需要维护两个数组的切割,还要注意区间的开闭性质。