617. 合并二叉树
错误点:只在递归函数dfs之前创建了一个节点node,整个递归过程只用同一个全局节点对象,则最后的node值为同一个(最后递归的结果),应该在递归函数里面创建node,使得每次递归都有一个新的node,因为这是一个新的树。
'错误做法:'
def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]:
node = TreeNode(0)
def dfs(node1, node2):
if node1 is None:
return node2
if node2 is None:
return node1
node.val = node1.val + node2.val
#node = TreeNode(node1.val + node2.val)
node.left = dfs(node1.left,node2.left)
node.right = dfs(node1.right,node2.right)
return node
终止条件:
原则:根据问题需求选择最小且必要的终止条件,确保覆盖所有边界情况,
if root is None:
return None '或其他默认值'
叶子节点检查(针对叶子节点执行特定操作,提前终止递归。)
if root.left is None and root.right is None:
# 处理叶子节点的逻辑
return root
'或其他返回值return 1'
特定值或条件检查(在满足特定条件时立即返回结果,减少不必要的递归。)
if root.val == target:
return root # 找到目标节点
多树同步终止(简化空树处理逻辑)
"处理逻辑1:直接复用非空树节点"
if tree1 is None:
return tree2 # 当一棵树为空时,直接返回另一棵树
"处理逻辑2:每个节点都创建一个node复杂版"
if root1 is None and root2 is None:
return None # 两节点都为空
if root1 is None:
return TreeNode(root2.val) # 仅root2存在,创建新节点
if root2 is None:
return TreeNode(root1.val) # 仅root1存在,创建新节点
示例:
def maxDepth(root):
if root is None: # 空节点深度为0
return 0
left_depth = maxDepth(root.left)
right_depth = maxDepth(root.right)
return max(left_depth, right_depth) + 1
def maxDepth(root):
if root is None: # 处理空树
return 0
if root.left is None and root.right is None: # 叶子节点深度为1
return 1
left_depth = maxDepth(root.left)
right_depth = maxDepth(root.right)
return max(left_depth, right_depth) + 1
700. 二叉搜索树中的搜索
'错误的:'
def dfs(node,val):
if node is None:
return
if node.val == val:
return node
'没有保存或者传递left / right子树找到结果后,这个结果如何传递给上层node节点,是断开的'
dfs(node.left,val)
dfs(node.right,val)
'正确的:'
def dfs(node,val):
if node is None:
return
if node.val == val:
return node
'左边left值保留在node同一层,即传递给node当层的值'
left = dfs(node.left,val)
if left:
return left
return dfs(node.right,val)
return dfs(root,val)
是否需要向上传递:
核心原则:是否传递结果取决于「父节点的操作是否依赖子树的返回值」,而与遍历顺序无关。
一、不需要传递结果的递归场景:
1. 纯操作型递归(无返回值)
执行某种操作(如遍历、修改节点),而非计算或搜索时,无需传递结果。子节点不需要被父节点使用,每个节点相互独立。父节点无需等待子树的「返回结果」。
def preorder_traversal(root):
if root is None:
return
print(root.val) # 操作:打印当前节点
preorder_traversal(root.left) # 递归左子树,无需返回值
preorder_traversal(root.right) # 递归右子树,无需返回值
2. 副作用记录结果(通过可变对象):
通过修改全局变量或传入的可变对象[]来隐式记录结果,无需显式返回。函数没有return
语句,直接修改传入的result
列表。
def collect_leaves(root, leaves=None):
if leaves is None:
leaves = []
if root is None:
return
if root.left is None and root.right is None:
leaves.append(root.val) # 副作用:修改列表
collect_leaves(root.left, leaves)
collect_leaves(root.right, leaves)
# 无需返回leaves,因为列表是可变对象,已被修改
二、需要传递结果的递归场景:
1. 计算型递归(需要汇总子结果)
父节点的深度需要基于左右子树的深度计算 ,通过return向上传递。
def tree_depth(root):
if root is None:
return 0
left_depth = tree_depth(root.left) # 传递左子树深度
right_depth = tree_depth(root.right) # 传递右子树深度
return max(left_depth, right_depth) + 1 # 汇总子结果
2. 搜索型递归(需要向上传递找到的目标)
虽然遍历顺序是前序,但本质是「搜索」而非纯遍历,需要将子树中找到的目标节点向上传递。不加return就是遍历整棵树了。
def search_node(root, target):
if root is None:
return None
if root.val == target:
return root # 找到目标,传递给父节点
left_result = search_node(root.left, target) # 传递左子树结果
if left_result:
return left_result
return search_node(root.right, target) # 传递右子树结果
98. 验证二叉搜索树
前序遍历:
def isValidBST(self, root: Optional[TreeNode], left=-inf, right=inf) -> bool:
if not root:
return True
x = root.val
'检查根节点值bool'
if x >= right or x <= left:
return False
'检查左右子树bool'
return self.isValidBST(root.left,left,x) and self.isValidBST(root.right,x,right)
后序遍历:
def isValidBST(self, root: Optional[TreeNode]) -> bool:
def dfs(node):
if not node:
return inf,-inf
l_min,l_max = dfs(node.left)
r_min,r_max = dfs(node.right)
x = node.val
'不符合条件,返回false(-inf,inf)'
if x <= l_max or x >= r_min:
return -inf,inf
'符合条件,确保每层都会有向上的返回值'
return min(l_min,x),max(r_max,x)
return dfs(root)[0] != -inf
530. 二叉搜索树的最小绝对差
二叉搜索树的顺序性,使用中序遍历更方便。
def getMinimumDifference(self, root: Optional[TreeNode]) -> int:
'记录更新遍历过的最小值'
ans = float('inf')
'指针记录当前遍历的节点值'
pre = float('inf')
def dfs(node):
if node is None:
return
dfs(node.left)
nonlocal ans, pre
'记录最小值'
ans = min(abs(node.val - pre),ans)
'更新当前节点值'
pre = node.val
dfs(node.right)
return ans
return dfs(root)
501. 二叉搜索树中的众数
def findMode(self, root: Optional[TreeNode]) -> List[int]:
ans = [] '记录结果的数组'
pre = None '指针'
current_count = 0 '当前值频率统计'
Max_count = 0 '最大频率值'
def dfs(node):
if not node:
return
nonlocal pre, ans, Max_count, current_count
dfs(node.left)
if node.val == pre:
current_count += 1
else:
current_count = 1
if current_count == Max_count:
ans.append(node.val)
elif current_count > Max_count:
ans = [node.val]
Max_count = max(current_count,Max_count)
pre = node.val
dfs(node.right)
dfs(root)
return ans
236. 二叉树的最近公共祖先
二叉搜索树LCA
二叉树LCA
这部分代码:
def lowestCommonAncestor(self, root, p, q):
'终止条件(根节点的早期检查,但非核心处理)'
if not root or root is q or root is p:
return root
'递归遍历左子树(获取左子树的结果)'
left = self.lowestCommonAncestor(root.left, p, q)
'递归遍历右子树(获取右子树的结果)'
right = self.lowestCommonAncestor(root.right, p, q)
'合并左右子树的结果(根节点的核心处理)'
if not left and not right:
return None
if not left:
return right
if not right:
return left
return root '左右子树各找到一个,当前节点即为LCA'