使用 DFS 检查二叉树中是不是存在路径不起作用
Posted
技术标签:
【中文标题】使用 DFS 检查二叉树中是不是存在路径不起作用【英文标题】:Checking If a path exists in a Binary Tree using DFS not working使用 DFS 检查二叉树中是否存在路径不起作用 【发布时间】:2021-09-29 03:01:41 【问题描述】:我需要检查二叉树中是否存在路径。我得到了一个元素列表和一个要遍历的二叉树。我正在使用 DFS 检查路径是否存在。这个想法是我应该找到从根节点到叶节点的路径是否存在。
如果我执行以下操作,我知道我可以找到路径是否存在...
class TreeNode:
def __init__(self, val, left=None, right=None):
self.val = val
self.left = left
self.right = right
def find_path(root, sequence):
if root is None:
return len(sequence) == 0
return find_path_helper(root, sequence, 0)
def find_path_helper(current_node, sequence, sequence_index):
if current_node is None:
return False
sequence_length = len(sequence)
if sequence_index >= sequence_length or current_node.val != sequence[sequence_index]:
return False
if current_node.left is None and current_node.right is None and sequence_index == sequence_length - 1:
return True
return find_path_helper(current_node.left, sequence, sequence_index + 1) or \
find_path_helper(current_node.right, sequence, sequence_index + 1
但是,我没有考虑代码效率的第一个想法是保留从根到叶的路径列表并将其与要找到的列表进行比较,但我无法让它工作,我不确定是什么我做错了。
class TreeNode:
def __init__(self, val, left=None, right=None):
self.val = val
self.left = left
self.right = right
def find_path(root, sequence):
if root is None:
return len(sequence) == 0
return find_path_helper(root, sequence, [])
def find_path_helper(current_node, sequence, current_sequence):
if current_node is None:
return False
current_sequence.append(current_node.val)
if current_node.left is None and current_node.right is None:
return current_sequence == sequence
return find_path_helper(current_node.left, sequence, current_sequence) or \
find_path_helper(current_node.right, sequence, current_sequence)
但即使为 true,也只会返回 false。我在想 current_sequence 从根遍历到叶子后会有当前路径。
以树为例
1
/ \
0 1
| |\
1 6 5
我需要检查路径 1 -> 1 -> 6 是否存在
下面是树的一个例子
root = TreeNode(1)
root.left = TreeNode(0)
root.right = TreeNode(1)
root.left.left = TreeNode(1)
root.right.left = TreeNode(6)
root.right.right = TreeNode(5)
sequence = [1, 1, 6]
print(find_path(root, sequence))
class TreeNode:
def __init__(self, val, left=None, right=None):
self.val = val
self.left = left
self.right = right
def find_path(root, sequence):
if root is None:
return len(sequence) == 0
return find_path_helper(root, sequence, [])
def find_path_helper(current_node, sequence, current_sequence):
if current_node is None:
return False
current_sequence.append(current_node.val)
if current_node.left is None and current_node.right is None:
return current_sequence == sequence
# if I pass in a copy of current_sequence it works
# I'm not sure why this does though
return find_path_helper(current_node.left, sequence, list(current_sequence)) or \
find_path_helper(current_node.right, sequence, list(current_sequence))
最后这段代码有效,但我不知道为什么我必须传递current_sequence
的副本
【问题讨论】:
你如何代表树? 发布的代码不是有效的 Python。 抱歉忘记添加def
。它是一棵二叉树。一个父节点不超过2个子节点
请提供调用find_path
的例子。
而TreeNode
的定义是……?
【参考方案1】:
当您将可变对象(如列表)传递给函数时,分配给它的局部变量参数不是列表中数据的副本。两个变量都引用同一个底层列表对象。通过一个变量对列表所做的更改反映在从另一个变量可见的列表上。
您可以通过一个简单的示例看到此行为:
>>> def foo(L):
... print(id(L))
... L[0] = 42
...
>>> X = [1, 2]
>>> id(X)
139874008311168
>>> foo(X)
139874008311168
>>> X
[42, 2]
在您的递归调用中,所有本地 current_sequence
变量都引用内存中的同一个列表。
当您的递归调用解决并且调用堆栈从未找到有效路径的左子树探索中弹回父调用范围时,current_sequence
列表仍会保留来自该失败遍历的不正确值。在探索正确的子树以使算法正常工作时,必须忽略这些值。
制作列表的副本通过使每个列表在每帧中成为不同的对象来解决问题,但效率低下。更好的是使用append()
和pop()
在每次调用时改变同一个列表,或者完全跳过二级列表并传递一个索引/深度参数来比较i
-th 节点和i
-th 列表索引:
def find_path(root, sequence, depth=0):
if (
root and
not root.left and
not root.right and
depth == len(sequence) - 1 and
root.data == sequence[depth]
):
return True
elif (
not root or
depth >= len(sequence) or
sequence[depth] != root.data
):
return False
return (find_path(root.left, sequence, depth + 1) or
find_path(root.right, sequence, depth + 1))
class Node:
def __init__(self, data, left=None, right=None):
self.data = data
self.left = left
self.right = right
if __name__ == "__main__":
r"""
1
/ \
2 3
/ / \
4 5 6
"""
root = Node(
1,
Node(
2,
Node(4),
),
Node(
3,
Node(5),
Node(6),
),
)
should_be_true = [[1, 3, 5], [1, 3, 6], [1, 2, 4]]
assert all(find_path(root, x) for x in should_be_true)
should_be_false = [
[1, 2, 5],
[1, 3, 4],
[1, 3],
[1, 3, 3, 3],
[1, 3, 5, 5],
[],
[1, 2],
]
assert all(not find_path(root, x) for x in should_be_false)
【讨论】:
以上是关于使用 DFS 检查二叉树中是不是存在路径不起作用的主要内容,如果未能解决你的问题,请参考以下文章