递归DFS实现二叉树根到目标节点路径打印的问题排查
问题分析与修复方案
你的代码之所以会让path包含所有遍历过的节点,核心问题出在默认参数陷阱、缺少回溯操作以及目标节点处理遗漏这几点上,具体分析和修复方案如下:
问题根源
- 可变默认参数的共享问题:Python中,像
path=[]这种可变默认参数会在函数定义时初始化一次,所有函数调用都会共享同一个列表实例。这意味着多次调用dfs时,path会累积之前调用的结果。 - 未做回溯处理:当遍历左子树失败后,你没有把当前节点从
path中移除,导致后续遍历右子树时,path里还保留着左子树遍历过的节点。 - 目标节点未加入路径:当找到目标节点时,你直接返回
True,但没有将当前节点的val加入path,最终路径会缺失目标节点本身。 - 空节点处理无效:
path = []只是给函数内的局部变量赋值,不会修改外部传入的path列表,完全起不到重置的作用。
修复方案(回溯法,空间效率高)
这是最常用的方式,通过回溯保证path始终只保留从根节点到当前遍历节点的路径:
def dfs(self, current, target, path=None): # 替换可变默认参数,每次调用无传入时新建空列表 if path is None: path = [] if current is None: return False # 先将当前节点加入路径 path.append(current.val) # 找到目标节点,直接返回True,路径已包含当前节点 if current.val == target.val: return True # 递归遍历左右子树,任一子树找到目标就返回True found = self.dfs(current.left, target, path) or self.dfs(current.right, target, path) if found: # 找到目标,保留当前路径 return True else: # 未找到目标,回溯:移除当前节点 path.pop() return False
修改说明
- 把默认参数改为
path=None,函数内部初始化空列表,彻底避免共享列表的问题。 - 进入函数先将当前节点加入
path,确保路径始终包含当前遍历的节点。 - 左右子树遍历失败后,用
path.pop()移除当前节点,实现回溯,保证path只保留有效路径。 - 找到目标节点时直接返回
True,此时path已经完整包含从根到目标的路径。
替代方案(传递新列表,无需回溯)
如果觉得回溯逻辑不好理解,可以每次递归时创建新的路径列表,这样左右子树的路径互不干扰:
def dfs(self, current, target, path=None): if path is None: path = [] if current is None: return False # 创建新路径,不修改原路径 new_path = path + [current.val] if current.val == target.val: # 找到目标,保存路径(可以用实例变量或返回值传递) self.target_path = new_path return True # 传递新路径递归遍历左右子树 return self.dfs(current.left, target, new_path) or self.dfs(current.right, target, new_path)
这种方式不需要回溯,但每次递归都会复制列表,空间复杂度略高,适合小型二叉树场景。
内容的提问来源于stack exchange,提问作者Darth.Vader
相关产品推荐
相关产品推荐

