Find Path to Specified Node in Binary Tree (Python)

淺唱寂寞╮ 提交于 2020-06-12 22:05:57

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!