[英]Binary tree: first common ancestor
在过去的几天里,我一直在与树木和python作斗争。 通常,是树木的递归给我带来了麻烦。 我要解决的问题是在二叉树中找到第一个共同祖先。 有许多解决方案声称可以做到这一点,但是它们都是针对二进制搜索树的,而不是针对二进制树的。 对于二叉树,节点没有排序,因此left小于right。 我知道我应该使用哪种方法,但是递归部分失败了:(编辑:问题表明我不能使用其他数据结构或存储)
class Node:
"""docstring for Node"""
def __init__(self, data):
self.data = data
self.left=None
self.right=None
def findNode(self,target):
if self==None:
return 0
if self.data==target:
return 1
return self.findNode(self.left,target) or self.findNode(self.right,target)
def firstCommonAncestor(self,p,q):
if self==None:
return 0
if self.left.data==p and self.right.data==q:
return self.data
if findNode(self.left,p) and findNode(self.right,q):
return 1
root=Node(2)
root.left=Node(5)
root.right=Node(4)
root.left.left=Node(9)
root.left.right=Node(7)
print firstCommonAncestor(root,9,7)
我编辑了代码以使问题更加清楚。 因为两个节点都存在,所以findNode(self.left,p)和findNode(self.right,q)应该返回1。 但是,当findNode(self.right,q)不在从根目录开始搜索时。 我知道我应该实现递归调用,但是我尝试过的一切都失败了。 如果有人可以提供一些有关我做错事情的指导,将不胜感激! (firstCommonAncestor尚未实现,因此这并不重要。它目前没有做太多事情)。 编辑:这是破解编码面试的一个问题。
(只是给您提示为什么它不起作用)
当您搜索y时,它不会返回到根。 您的代码在做正确的事。 之所以找不到Node(7),是因为您的数据。
这是你的树。
2
|
-------
5 4
-------
9 7
您的x搜索是findNode(Node(5),9),找到9。
当你的Ÿ搜索findNode(节点(4),7),这当然会永远找不到7
希望能有所帮助。
另一个提示:您的实例方法不在类之内,而只是普通的全局方法(这不仅仅是缩进的问题,因为您还会以错误的方式调用它们)。 这是findNode
的正确定义:
class Node:
"""docstring for Node"""
def __init__(self, data):
self.data = data
self.left=None
self.right=None
def findNode(self,target):
result = None
if self.data == target:
return self
result = self.left.findNode(target) if self.left else None
if not result:
result = self.right.findNode(target) if self.right else None
return result
def firstCommonAncestor(self, p, q):
pass #TODO
在findNode
方法中,您还具有如何调用它的示例。 您还应该在firstCommonAncestor
方法中解决此firstCommonAncestor
。
class Node:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def isAncestor(self, p, q):
ret = 0
if self.data == None:
return ret
if (self.data == p):
ret += 1
if self.data == q:
ret += 1
if ret == 2:
return ret
if self.left!=None:
ret += self.left.isAncestor(p, q)
if ret == 2:
return ret
if self.right!=None:
return ret + self.right.isAncestor(p ,q)
return ret
def commonAncestor(self, p, q):
if q == p and (self.left.data == q or self.right.data == q):
return self
lNodes = self.left.isAncestor(p, q)
if lNodes == 2:
if self.left.data == p or self.left.data == q:
return self.left
else:
return self.left.commonAncestor(p, q)
elif lNodes == 1:
if self.data == p:
return p
elif self.data == q:
return q
rNodes = self.right.isAncestor(p, q)
if rNodes == 2:
if self.right.data == p or self.right.data == q:
return self.right
else:
return self.right.commonAncestor(p, q)
elif rNodes == 1:
if self.data == p:
return p
elif self.data == q:
return q
if lNodes == 1 and rNodes ==1:
return self
else:
return None
"""
2
/ \
5 4
/ \ / \
9 7 11
\
12
"""
if __name__ == '__main__':
root=Node(2)
root.left=Node(2)
root.right=Node(4)
root.right.right=Node(11)
root.left.left=Node(9)
root.left.right=Node(7)
root.right.right.right=Node(12)
common = root.commonAncestor(2,2)
if common != None:
print common.data
else:
print "Not found"
编辑:重新设计的解决方案,使其更清洁并解决评论中的问题
有一个非常有效的解决方案,但要复杂一些。 它涉及到钻入树并跟踪备份时是否找到第一个或第二个值。 如果某个时候您发现(第一个和第二个)都返回了该节点,那么它将是您的共同祖先。
这是一种更有效的解决方案,但是如果您有DUPLICATES,则它不起作用,但是它可以帮助您了解构思并解决重复的情况:
class Node:
"""docstring for Node"""
def __init__(self, data):
self.data = data
self.left=None
self.right=None
def union(self, u1, u2):
res = u1[0] or u2[0], u1[1] or u2[1], u1[2] or u2[2]
if res[0] and res[1] and not res[2]:
return res[0], res[1], self
return res
def doCommon(self, p, q):
# recursion base case
l = (False, False, None)
r = (False, False, None)
if self.left:
l = self.left.doCommon(p, q)
if self.right:
r = self.right.doCommon(p, q)
res = self.union(l, r)
if res[0] and res[1]:
return res
if self.data == p:
return self.union((True, False, None), res)
if self.data == q:
return self.union((False, True, None), res)
return res
def common(self, p, q):
return self.doCommon(p, q)[2]
if __name__ == '__main__':
root=Node(2)
root.left=Node(5)
root.right=Node(4)
root.left.left=Node(9)
root.left.right=Node(7)
res = root.common(9,7)
if res != None:
print res.data
else:
print "Not found"
由于没有排序树,因此无论如何您都必须搜索很多树。 并且由于不允许您使用额外的数据结构,因此有重复很多搜索的危险。
因此,递归到叶节点一次,然后返回返回数据可能是最有效的。 这是O(n),但单次搜索也是如此。
所以这就是下面的代码想要做的。 搜索方法返回(a's parent, b's parent)
,如果它们不同,但是都设置了,那么我们在共同的祖先。
def search(self, a, b):
ap1 = ap2 = ap3 = bp1 = bp2 = bp3 = None
# parents to left
if self.left:
ap1, bp1 = self.left.search(a, b)
# parents to right
if self.right:
ap2, bp2 = self.right.search(a, b)
# are we an immediate "parent" ourselves?
if self.data == a:
ap3 = self
elif self.data == b:
bp3 = self
# only one of the above can succeed, so find it
ap = ap1 or ap2 or ap3
bp = bp1 or bp2 or bp3
# if we are the point where two paths meet at the common
# ancestor, return ourselves
if ap and bp and ap != bp:
return self, self
# otherwise, return what we have
else:
return ap, bp
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.