算法基础之二叉树相关实战
3.路径和相关题目
3.1介绍
3.2真题分析
3.2.1路径总和(112)
#leetcode 112 方法1
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if root == None:
return False
# 当前节点是叶子,检查 root.val 值是否为 sum
if root.left == None and root.right == None and root.val == sum:
return True
# 当前节点不是叶子,对它的所有孩子节点,递归调用 hasPathSum() 函数
return self.hasPathSum(root.left,sum-root.val) or self.hasPathSum(root.right,sum-root.val)
#leetcode 112 方法2
class Solution:
def hasPathSum(self, root: TreeNode, sum: int) -> bool:
if root == None:
return False
stack = [(root,sum)]
while stack:
node,sum = stack.pop()
# 判断叶子节点是否满足了条件
if node.left == None and node.right == None and node.val == sum:
return True
# 左节点不为空,我们把左节点和剩余值打包压栈
if node.left != None:
stack.append((node.left,sum-node.val))
# 右节点不为空,我们把右节点和剩余值打包压栈
if node.right != None:
stack.append((node.right,sum-node.val))
return False
3.2.2路径总和2(113)
#leetcode113 方法1
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
# 辅助函数(因为需要一个变量记录路径)
def helper(root, sum, temp):
if root == None:
return
# 路径和满足sum,路径添加到结果数组res
if root.left == None and root.right == None and root.val == sum:
temp += [root.val]
res.append(temp)
# 递归搜索左右子树,传入剩余和以及路径
helper(root.left,sum-root.val,temp+[root.val])
helper(root.right,sum-root.val,temp+[root.val])
res = []
helper(root,sum,[])
return res
#leetcode113 方法2
class Solution:
def pathSum(self, root: TreeNode, sum: int) -> List[List[int]]:
if root == None:
return []
res = []
temp = []
stack = [(root,sum,temp)]
while stack:
node,sum,temp = stack.pop()
# 判断叶子节点是否满足了条件
if node.left == None and node.right == None and node.val == sum:
temp += [node.val]
res.append(temp)
if node.left != None:
stack.append((node.left,sum-node.val,temp + [node.val]))
if node.right != None:
stack.append((node.right,sum-node.val,temp + [node.val]))
return res
3.2.3二叉树中的最大路径和(124)
3.2.4求根到叶子节点数字之和(129)
#leetcode129 递归
class Solution:
def sumNumbers(self, root: TreeNode) -> int:
def helper(root, nums):
if root == None:
return 0
# 更新路径和
nums *= 10
nums += root.val
# 如果已经是叶子节点,保存路径和到列表中
if root.left == None and root.right == None:
res.append(nums)
if root.left != None:
helper(root.left,nums)
if root.right != None:
helper(root.right,nums)
res = []
helper(root,0)
return sum(res)
#leetcode129 迭代
class Solution:
def sumNumbers(self, root: TreeNode) -> int:
if root == None:
return 0
stack = [(root,0)]
res = []
while stack:
node,nums = stack.pop()
# 更新路径和
nums *= 10
nums += node.val
# 如果已经是叶子节点,保存路径和到列表中
if node.left == None and node.right == None:
res.append(nums)
if node.left != None:
stack.append((node.left,nums))
if node.right != None:
stack.append((node.right,nums))
return sum(res)
3.2.5 二叉树中的最大路径和(124)
#leetcode 124
class Solution:
def __init__(self):
self.maxSum = float("-inf")
def maxPathSum(self, root: TreeNode) -> int:
def maxGain(node):
if not node:
return 0
# 递归计算左右子节点的最大贡献值
# 只有在最大贡献值大于 0 时,才会选取对应子节点
leftGain = max(maxGain(node.left), 0)
rightGain = max(maxGain(node.right), 0)
# 节点的最大路径和取决于该节点的值与该节点的左右子节点的最大贡献值
priceNewpath = node.val + leftGain + rightGain
# 更新答案
self.maxSum = max(self.maxSum, priceNewpath)
# 返回节点的最大贡献值
return node.val + max(leftGain, rightGain)
maxGain(root)
return self.maxSum
3.2.6 二叉树的所有路径(257)
#leetcode257
class Solution:
def binaryTreePaths(self, root: TreeNode) -> List[str]:
if root == None:
return None
res = []
queue = [(root,'')]
while queue:
temp = ''
length = len(queue)
for _ in range(length):
node,temp = queue.pop(0)
temp += str(node.val)
# 如果是叶子节点,记录路径
if node.left == None and node.right == None:
res.append(temp)
# 格式要求
temp += '->'
if node.left != None:
queue.append((node.left,temp))
if node.right != None:
queue.append((node.right,temp))
return res
4.二叉树的构建相关题目
4.1介绍
4.2真题分析
4.2.1从前序与中序遍历序列构造二叉树(105)
#leetcode 105
class Solution(object):
def buildTree(self, preorder, inorder):
if not (preorder and inorder):
return None
# 根据前序数组的第一个元素,就可以确定根节点
root = TreeNode(preorder[0])
# 用preorder[0]去中序数组中查找对应的元素
mid_idx = inorder.index(preorder[0])
# 递归的处理前序数组的左边部分和中序数组的左边部分
# 递归处理前序数组右边部分和中序数组右边部分
root.left = self.buildTree(preorder[1:mid_idx+1],inorder[:mid_idx])
root.right = self.buildTree(preorder[mid_idx+1:],inorder[mid_idx+1:])
return root
4.2.2从中序与后续遍历序列构造二叉树(106)
#leetcode106
class Solution(object):
def buildTree(self, inorder, postorder):
if not (inorder and postorder):
return None
# 将中序数组的下标、值保存到map中省去解法一中线性查找
d = {val:idx for idx,val in enumerate(inorder)}
self.post_idx = len(postorder)-1
def dfs(left,right):
if left>right:
return None
# 从后序数组中拿最后一个元素,根据这个元素去map中找到中序数组对应的index
# 然后递归的处理右边[index+1,right],递归处理左边[left,index-1]
val = postorder[self.post_idx]
self.post_idx -= 1
root = TreeNode(val)
index = d[val]
root.right = dfs(index+1,right)
root.left = dfs(left,index-1)
return root
return dfs(0,len(inorder)-1)
4.2.3根据前序和后续遍历构造二叉树(889)
#leetcode 889
class Solution(object):
def constructFromPrePost(self, pre, post):
def dfs(pre,post):
if not pre:
return None
# 数组长度为1时,直接返回即可
if len(pre)==1:
return TreeNode(pre[0])
# 根据前序数组的第一个元素,创建根节点
root = TreeNode(pre[0])
# 根据前序数组第二个元素,确定后序数组左子树范围
left_count = post.index(pre[1])+1
# 递归执行前序数组左边、后序数组左边
root.left = dfs(pre[1:left_count+1],post[:left_count])
# 递归执行前序数组右边、后序数组右边
root.right = dfs(pre[left_count+1:],post[left_count:-1])
# 返回根节点
return root
return dfs(pre,post)