You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python二叉树遍历结果异常:字符串与列表传参差异求助

为什么递归中字符串和列表作为参数时结果不同?

你的问题核心在于Python中字符串是不可变类型,而列表是可变类型,这直接导致了两者在递归传递时的行为差异,我给你拆解清楚:

1. 字符串的正确行为解析

在你的代码里,path += str(root.val) 这行看起来是修改了path,但实际上因为字符串不可变,这行代码会创建一个全新的字符串对象,并把新对象的引用赋值给当前作用域的path变量。

每次递归调用trav时,传递的都是这个新字符串的引用——也就是说,每个递归分支的path都是独立的,不会和其他分支互相干扰。当你到达叶子节点时,path刚好是当前路径的字符拼接,'->'.join(path) 会把每个字符用->连接,刚好得到正确的路径字符串。

2. 列表的错误原因:引用传递与可变对象

而列表temp的情况完全不同:

  • temp.append(root.val) 是直接在原列表对象上修改,因为列表是可变类型。
  • 你在第一次调用trav时传入的是同一个temp列表的引用,所有递归分支共享这个列表对象。当递归深入左子树时,你往temp里加了节点值;递归回溯后再走右子树时,temp里已经包含了左子树的节点值,没有被清除,最终所有路径的节点都会累积到temp里,导致self.path_temp的结果错误。

你问“Python中的列表是否在内存中具有持久性”,更准确的说法是:列表作为可变对象,在内存中是一个持续存在的实体,所有持有该对象引用的地方,看到的都是同一个对象的状态。修改操作会直接改变这个实体的内容,而不是创建新对象。

3. 修正列表版本的两种方案

要让path_temp得到正确结果,有两种常用思路:

方案一:回溯法(推荐,内存效率更高)

在递归调用后,撤销对temp的修改,把当前添加的节点值移除:

def binaryTreePaths(self, root: TreeNode) -> List[str]:
    self.path = []
    temp = []
    self.path_temp = []
    def trav(root, path, temp):
        if root:
            path += str(root.val)
            temp.append(root.val)
            if root.right is None and root.left is None:
                self.path.append('->'.join(path))
                # 注意这里要把temp里的数字转成字符串再join
                self.path_temp.append('->'.join(map(str, temp)))
            trav(root.left, path, temp)
            trav(root.right, path, temp)
            temp.pop()  # 回溯:移除当前节点,恢复temp的状态
    trav(root, '', temp)
    print(self.path)
    print(self.path_temp)

方案二:传递列表副本

每次递归时,创建一个新的列表副本传递进去,这样每个分支都用自己独立的列表:

def binaryTreePaths(self, root: TreeNode) -> List[str]:
    self.path = []
    temp = []
    self.path_temp = []
    def trav(root, path, temp):
        if root:
            new_path = path + str(root.val)
            # 创建新列表,包含原temp的所有元素加上当前节点值
            new_temp = temp + [root.val]
            if root.right is None and root.left is None:
                self.path.append('->'.join(new_path))
                self.path_temp.append('->'.join(map(str, new_temp)))
            trav(root.left, new_path, new_temp)
            trav(root.right, new_path, new_temp)
    trav(root, '', temp)
    print(self.path)
    print(self.path_temp)

最后再总结一下关键区别

  • 不可变类型(字符串、整数、元组):任何“修改”操作都会生成新对象,原对象保持不变,传递时不会出现跨分支的干扰。
  • 可变类型(列表、字典、集合):修改操作直接作用于原对象,传递的是对象引用,所有共享该引用的地方都会看到修改结果。

内容的提问来源于stack exchange,提问作者pat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.08 20:33:14