112、路径总和
给你二叉树的根节点 root 和一个表示目标和的整数 targetSum 。判断该树中是否存在 根节点到叶子节点 的路径,这条路径上所有节点值相加等于目标和 targetSum 。如果存在,返回 true ;否则,返回 false 。
叶子节点 是指没有子节点的节点。
示例1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,null,1], targetSum = 22
输出:true
示例2:
输入:root = [1,2,3], targetSum = 5
输出:false
示例3:
输入:root = [], targetSum = 0
输出:false
思路
这道题比较直观的想法是用迭代,找到目标值,这里要注意路径的终止条件为叶子结点。
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)
广度优先遍历
class Solution:
def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool:
if not root: return False
# 这里用两个栈来映射当前结点以及当前结点路径的总和
queue = [root]
# 这里也可以用hash来存储,不过由于这两个queue是同步操作,所以值是一一对应的
queue_val = [root.val]
while queue:
cur = queue.pop(0)
val = queue_val.pop(0)
# 当前结点如果没有左子节点和右子结点时,判断是否满足条件
# 如果满足条件,返回即可,如果不满足,继续遍历
if not cur.left and not cur.right:
if val == sum: return True
continue
if cur.left:
queue.append(cur.left)
queue_val.append(cur.left.val + val)
if cur.right:
queue.append(cur.right)
queue_val.append(cur.right.val + val)
return False
113、路径总和2
给你二叉树的根节点 root 和一个整数目标和 targetSum ,找出所有 从根节点到叶子节点 路径总和等于给定目标和的路径。
叶子节点 是指没有子节点的节点。
示例1:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:[[5,4,11,2],[5,8,4,5]]
示例2:
输入:root = [1,2,3], targetSum = 5
输出:[]
示例3:
输入:root = [1,2], targetSum = 0
输出:[]
思路
这道题和上面的比较相似,只不过这里需要返回所有的路径。
class Solution:
def pathSum(self, root: Optional[TreeNode], targetSum: int) -> List[List[int]]:
if not root: return []
# 如果没有子节点,并且结点值等于给定的值,返回结点值
if not root.left and not root.right and root.val == targetSum:
return [[root.val]]
# 由于方法都是返回的数组,直接拼接即可,然后在每个里层元素添加头结点
ans = self.pathSum(root.left, targetSum - root.val) + self.pathSum(root.right, targetSum - root.val)
[item.insert(0, root.val)for item in ans]
return ans
124、二叉树中的最大路径和
路径 被定义为一条从树中任意节点出发,沿父节点-子节点连接,达到任意节点的序列。同一个节点在一条路径序列中 至多出现一次 。该路径 至少包含一个 节点,且不一定经过根节点。
路径和 是路径中各节点值的总和。
给你一个二叉树的根节点 root ,返回其 最大路径和 。
示例1:
输入:root = [1,2,3]
输出:6
解释:最优路径是 2 -> 1 -> 3 ,路径和为 2 + 1 + 3 = 6
示例2:
输入:root = [-10,9,20,null,null,15,7]
输出:42
解释:最优路径是 15 -> 20 -> 7 ,路径和为 15 + 20 + 7 = 42
思路:
对于当前节点来说,当前节点的路径和应该是当前节点值+左子树路径 + 右子树路径,那么最大值应该是需要判断左右子树的路径和大于零才加到路径上。那么对于子树的最大路径应该是取子节点以及其左右子树的最大值。
class Solution:
def maxPathSum(self, root: Optional[TreeNode]) -> int:
self.ans = float('-inf')
def dfs(root):
if not root: return 0
# 获取左右子树的值
left = max(dfs(root.left), 0)
right = max(dfs(root.right), 0)
# 当前节点的最大路径和应该是当前节点值 + 左子树 + 右子树(大于0)
# 并更新结果值
cur = root.val + left + right
self.ans = max(self.ans, cur)
# 而当前节点的返回值应该是当前值 + 左右子树(大于0)的值
return root.val + max(left, right)
dfs(root)
return self.ans
437、路径总和3
给定一个二叉树的根节点 root ,和一个整数 targetSum ,求该二叉树里节点值之和等于 targetSum 的 路径 的数目。
路径 不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点)。
示例1:
输入:root = [10,5,-3,3,2,null,11,3,-2,null,1], targetSum = 8
输出:3
示例2:
输入:root = [5,4,8,11,null,13,4,7,2,null,null,5,1], targetSum = 22
输出:3
思路
class Solution:
def pathSum(self, root: TreeNode, targetSum: int) -> int:
def dfs(root, targetSum):
if not root: return 0
sum = 0
if root.val == targetSum:
sum += 1
sum += dfs(root.left, targetSum - root.val) + dfs(root.right, targetSum - root.val)
return sum
if not root: return 0
return dfs(root, targetSum) + self.pathSum(root.left, targetSum) + self.pathSum(root.right, targetSum)
前缀和:
如果在某条路径上,发现该路径的和减去targetSum之前出现过,那么就说明在这条路径上肯定有子路径到该结点的和为targetSum。
class Solution:
def pathSum(self, root: TreeNode, targetSum: int) -> int:
prefixSum = collections.defaultdict(int)
prefixSum[0] = 1
def dfs(root, cur):
if not root: return 0
sum = 0
cur += root.val
# 这里先看之前有没有满足的值
sum += prefixSum[cur - targetSum]
# 由于cur是先于cur-targetSum的,所以这里设置1,那么后面的cur-targetSum就可能取到该值
prefixSum[cur] += 1
sum += dfs(root.left, cur) + dfs(root.right, cur)
# 处理完成之后,将这里进行减一操作,避免重复计算
prefixSum[cur] -= 1
return sum
return dfs(root, 0)