二叉树的路径问题(系列)
· 约 6 分钟阅读 · – 次阅读
leetcode
112. 路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。 叶子节点 是指没有子节点的节点。
深度优先遍历
# 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
if not root.left and not root.right:
return root.val == targetSum
return self.hasPathSum(root.left, targetSum-root.val) or self.hasPathSum(root.right, targetSum-root.val)
广度优先遍历
# 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
node_queue = collections.deque([root])
num_queue = collections.deque([root.val])
while node_queue:
node = node_queue.popleft()
num = num_queue.popleft()
if not node.left and not node.right:
if num == targetSum:
return True
else:
if node.left:
node_queue.append(node.left)
num_queue.append(num+node.left.val)
if node.right:
node_queue.append(node.right)
num_queue.append(num+node.right.val)
return False
113. 路径总和 II
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
深度优先遍历
重点在弹出的动作,方便下次遍历
# 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]]:
def dfs(root, path, ans, targetSum):
# print(targetSum)
if not root:
return
path.append(root.val)
if not root.left and not root.right:
if targetSum == root.val:
ans.append(list(path))
else:
if root.left:
dfs(root.left, path, ans, targetSum-root.val)
if root.right:
dfs(root.right, path, ans, targetSum-root.val)
# 有点回溯的思路了,需要将加入的根节点弹出
path.pop()
path = []
ans = []
dfs(root, path, ans, targetSum)
return ans
广度优先遍历
在找到和相等的节点时,需要反查到根节点。为此,需要有一个dict记录节点的父节点
理解起来相对更容易一点
# 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]]:
parents = dict()
ans = []
def getPath(node):
path = collections.deque()
while node:
path.appendleft(node.val)
node = parents[node]
ans.append(list(path))
if not root:
return ans
parents[root] = None
node_queue = collections.deque([root])
num_queue = collections.deque([0])
while node_queue:
node = node_queue.popleft()
num = num_queue.popleft()
total = num + node.val
if not node.left and not node.right:
# print(node.val,total,targetSum)
if total == targetSum:
getPath(node)
else:
if node.left:
parents[node.left] = node
node_queue.append(node.left)
num_queue.append(total)
if node.right:
parents[node.right] = node
node_queue.append(node.right)
num_queue.append(total)
return ans
437. 路径总和 III
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
深度优先遍历
定义rootSum为从root节点开始往下得到的路径和为目标值的路径个数 则原问题等于三个子问题的和: 根节点往下路径和为目标值的个数 左子树的解 右子树的解
# 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) -> int:
def rootSum(root, targetSum):
ans = 0
if not root:
return ans
if root.val == targetSum:
ans += 1
ans += rootSum(root.left, targetSum-root.val)
ans += rootSum(root.right, targetSum-root.val)
return ans
if not root:
return 0
return rootSum(root, targetSum) + self.pathSum(root.left, targetSum) + self.pathSum(root.right, targetSum)
前缀路径和
【经典方法】 用dict记录从根节点到当前节点的路径(不含当前节点)上每个节点的路径和
# 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) -> int:
prefix_sum = collections.defaultdict(int)
prefix_sum[0] = 1
def dfs(root, cur):
ans = 0
if not root:
return ans
cur += root.val
ans += prefix_sum[cur-targetSum]
prefix_sum[cur] += 1
if root.left:
ans += dfs(root.left, cur)
if root.right:
ans += dfs(root.right, cur)
# 我们利用深度搜索遍历树,当我们退出当前节点时,我们需要及时更新已经保存的前缀和。
prefix_sum[cur] -= 1
return ans
return dfs(root, 0)
257. 二叉树的所有路径
给你一个二叉树的根节点 root ,按 任意顺序 ,返回所有从根节点到叶子节点的路径。
叶子节点 是指没有子节点的节点。
深度优先遍历
题目要返回的是字符串形式的路径,表示无语
# 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 binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
def dfs(root, ans, path):
if not root:
return
path.append(str(root.val))
if not root.left and not root.right:
ans.append("->".join(path))
else:
if root.left:
dfs(root.left, ans, path)
if root.right:
dfs(root.right, ans, path)
path.pop()
ans = []
path = []
dfs(root, ans, path)
return ans
广度优先遍历
# 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 binaryTreePaths(self, root: Optional[TreeNode]) -> List[str]:
def getPath(node):
path = collections.deque()
while node:
path.appendleft(str(node.val))
node = parents[node]
ans.append('->'.join(path))
ans = []
if not root:
return ans
parents = dict()
parents[root] = None
node_queue = collections.deque([root])
while node_queue:
node = node_queue.popleft()
if not node.left and not node.right:
getPath(node)
else:
if node.left:
parents[node.left] = node
node_queue.append(node.left)
if node.right:
parents[node.right] = node
node_queue.append(node.right)
return ans
124. 二叉树中的最大路径和
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和 。
递归
# 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.ans = float("-inf")
def maxPathSum(self, root: Optional[TreeNode]) -> int:
# maxGain计算以该节点为起点的一条路径,使得该路径上的节点值之和最大的贡献值
def maxGain(root):
if not root:
return 0
left = max(maxGain(root.left), 0)
right = max(maxGain(root.right), 0)
self.ans = max(self.ans, left+right+root.val)
return max(left, right) + root.val
maxGain(root)
return self.ans