问题
I'm having trouble computing the path from the root to a specified node in a binary tree (this is specifically about a Python solution to this problem).
Here's an example. Given the binary tree below, if I specify the node whose value is 4, I want to return [1, 2, 4]. If I specify the node whose value is 5, I want to return [1, 2, 5].
1
/ \
2 3
/ \
4 5
Here's my attemped solution.
class TreeNode:
def __init__(self, x):
self.val = x
self.left = None
self.right = None
def path(root, k, l=[]):
if not root:
return []
if root.val == k:
return l
# Pre-order traversal: Visit root, then left, then right.
l.append(root.val)
path(root.left, k, l)
path(root.right, k, l)
return l
Now if I run this
>>> a = TreeNode(1)
>>> b = TreeNode(2)
>>> c = TreeNode(3)
>>> d = TreeNode(4)
>>> e = TreeNode(5)
>>> a.left = b
>>> a.right = c
>>> b.left = d
>>> b.right = e
>>> path(a, 4) # should be [1, 2, 4]
[1, 2, 5, 3]
You can see that I don't get the expected. I'm sure it has to do with my traversal algorithm, but I can't figure out where I'm going wrong. Any help is greatly appreciated.
回答1:
The missing 4
is caused by the fact that you never append it. In your success case:
if root.val == k:
return l
… you need to d this:
if root.val == k:
l.append(root.val)
return l
The extra 3
and 5
are caused by the fact that you always append the value in the intermediate case, even for the nodes where you're going to backtrack.
You can fix that by only appending it if either of the recursive calls returns a non-empty list, but then of course you'll have the nodes out of order. The easiest fix for that is to intentionally get the nodes out of order:
# Pre-order traversal: Visit root, then left, then right.
if path(root.left, k, l) or path(root.right, k, l):
l.append(root.val)
… and then reverse the list at the end, e.g., in a wrapper function:
def path2(root, k):
return list(reversed(path(root, k)))
However, there's still one problem left in your code, right here:
def path(root, k, l=[]):
That []
that's the default value for l
gets created one time, when the def
is executed, and then reused on every call. That means that path2(a, 4)
will return the right answer the first time, [1, 2, 4]
, but when you call it a second time, it'll keep appending to that same list and return [1, 2, 4, 1, 2, 4]
.
There are a couple idiomatic ways around this, but in our case, since we're already using that path2
wrapper function, we might as well just fix it there:
def path2(root, k):
return list(reversed(path(root, k, [])))
… and then get rid of the default value on path
.
However, you might want to consider starting over with an easier-to-understand version:
def path(root, k):
if not root:
return []
if root.val == k:
return [root.val]
res = path(root.left, k)
if res:
return [root.val] + res
res = path(root.right, k)
if res:
return [root.val] + res
return []
(You can make this is a bit shorter; I went out of my way to make everything explicit here.)
For many recursive problems, inverting them and passing up an accumulator is an important optimization, because tail-call elimination can remove one of the branches from the stack. Even though Python doesn't do TCE, it's still worth learning how to do things the tail-calling way, just for your own understanding (and in case you ever write code in another language, of course). But learn how to do the simpler version first, and only then try to invert it.
来源:https://stackoverflow.com/questions/49227541/find-path-to-specified-node-in-binary-tree-python