Python循环破坏二叉树最大路径和递归算法问题排查
二叉树最大路径和:全负节点边缘用例的问题与修复
问题背景
处理二叉树最大路径和问题时,针对全负节点的边缘用例,添加的一段for循环代码出现互斥问题:
- 注释循环时,除全负节点用例返回错误的0外,其余用例结果正确;
- 不注释循环时,仅全负节点用例正确,其余所有用例结果错误。
原始代码
class Node(): def __init__(self, value, binList): self.value = value self.left_child = None self.right_child = None self.binList = binList def binTree(binList, i=0): if i < len(binList): value = binList[i] if value == None: return node = Node(value, binList) node.left_child = binTree(binList, i * 2 + 1) node.right_child = binTree(binList, i * 2 + 2) return node def pathFinder(root): neg_max = float("-inf") # for x in root.binList: # if x != None: # neg_max = max(neg_max, x) # if neg_max < 0 and neg_max != float("-inf"): # return neg_max try: left_sum = max(0, pathFinder(root.left_child)) right_sum = max(0, pathFinder(root.right_child)) current_path_sum = root.value + left_sum + right_sum return max(current_path_sum, max(left_sum, right_sum)) except: return 0 # 测试用例 print("expected 6, output:",pathFinder(binTree([1,2,3]))) print("expected 42, output:",pathFinder(binTree([-10,9,20,None,None,15,7]))) print("expected 35, output:",pathFinder(binTree([-10,-9,20,None,None,15,-7]))) print("expected 20, output:",pathFinder(binTree([-10,-9,-20,None,None,15,-7,None,None,None,None,5]))) print("expected -1, output:",pathFinder(binTree([-1,-2,-3])))
两种输出情况
- 注释循环时输出:
expected 6, output: 6 expected 42, output: 42 expected 35, output: 35 expected 20, output: 20 expected -1, output: 0
- 不注释循环时输出:
expected 6, output: 1 expected 42, output: 20 expected 35, output: 20 expected 20, output: 0 expected -1, output: -1
错误原因分析
- 全局状态破坏递归局部性:每个
Node实例都存储了完整的输入列表binList,导致递归的每一层都会遍历整个树的所有节点。当树不全是负数时,循环不会触发返回,但递归逻辑本身存在缺陷,导致后续计算完全错误。 - 递归逻辑混淆核心概念:原始
pathFinder函数错误地将「子树内部的最大路径和」和「向上传递的路径和」混为一谈,返回值既不是正确的局部最大和,也不是能传递给父节点的有效路径和。比如处理[1,2,3]时,子节点的递归返回值错误,导致根节点计算出的路径和仅为1。 - 异常处理滥用:用
try-except捕获空节点的访问异常并直接返回0,在全负场景下会错误舍弃负节点的贡献,导致返回0而非最大的负数。
修复方案
核心思路
- 移除全局列表的存储,让递归仅关注当前节点的局部状态;
- 拆分递归逻辑:用一个变量跟踪全局最大路径和,递归函数仅返回当前节点能向上传递的有效路径和;
- 自然处理全负场景:当所有子树贡献为负时,仅保留当前节点的值作为向上传递的路径和,全局变量会自动记录最大的负数。
修正后的代码
class Node(): def __init__(self, value): self.value = value self.left_child = None self.right_child = None def binTree(binList, i=0): if i < len(binList): value = binList[i] if value is None: return None node = Node(value) node.left_child = binTree(binList, i * 2 + 1) node.right_child = binTree(binList, i * 2 + 2) return node def maxPathSum(root): max_sum = float("-inf") def dfs(node): nonlocal max_sum if not node: return 0 # 计算左右子树的有效贡献(负贡献则舍弃,取0) left_contribution = max(dfs(node.left_child), 0) right_contribution = max(dfs(node.right_child), 0) # 更新全局最大路径和(当前节点作为路径顶点的情况) current_path_sum = node.value + left_contribution + right_contribution if current_path_sum > max_sum: max_sum = current_path_sum # 返回当前节点能向上传递的最大路径和(只能选左或右分支+当前节点) return node.value + max(left_contribution, right_contribution) dfs(root) return max_sum # 测试用例验证 print("expected 6, output:", maxPathSum(binTree([1,2,3]))) print("expected 42, output:", maxPathSum(binTree([-10,9,20,None,None,15,7]))) print("expected 35, output:", maxPathSum(binTree([-10,-9,20,None,None,15,-7]))) print("expected 20, output:", maxPathSum(binTree([-10,-9,-20,None,None,15,-7,None,None,None,None,5]))) print("expected -1, output:", maxPathSum(binTree([-1,-2,-3])))
修正点说明
- 移除
Node类中的binList属性,避免递归中访问全局数据; - 使用嵌套的
dfs函数实现递归,通过nonlocal变量max_sum跟踪全局最大路径和; dfs函数返回当前节点能向上传递的最大路径和,确保父节点能正确计算包含当前节点的路径;- 当处理全负节点时,左右子树的贡献会被视为0,
current_path_sum等于当前节点的值,max_sum会记录所有节点中的最大值(即最大的负数)。
测试结果
修正后的代码所有测试用例均输出正确结果:
expected 6, output: 6 expected 42, output: 42 expected 35, output: 35 expected 20, output: 20 expected -1, output: -1
内容的提问来源于stack exchange,提问作者didrikm
相关产品推荐
相关产品推荐

