https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/
这里是BT不是BST,思路就是找到root到p和q的path然后找到最后的一个交点。要注意如何find Path。
如何用递归
http://bookshadow.com/weblog/2015/07/13/leetcode-lowest-common-ancestor-binary-tree/
思路1 findPath。。。用post-order
class Solution(object):
def findPath(self, root, target):
stack = []
pre = None
while stack or root:
if root:
stack.append(root)
root = root.left
else:#这里用的是post order。因为先遍历左子树,再右子树,最后再root,scan root的时候就是path
peek = stack[-1]# the first value of peek should be the most left node
if peek.right and pre != peek.right:
root = peek.right#这里往右走,没有pop 回溯,只有在回溯的时候才需要pop
else:#一直到没有右子树,或者右子树已经遍历完了。
if peek == target:
return stack
pre = stack.pop()
root = None #这里要记住这句话
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
path1 = self.findPath(root, p)
path2 = self.findPath(root, q)
i = 0
len1, len2 = len(path1), len(path2)
while i < min(len1, len2) and path1[i] == path2[i] :
i += 1
i -= 1
return path1[i]
这里注意不能直接用preorder 带stack的code,直接在push一个element进stack之后就判断是否为要找的node。反例[2, null, 1], 对于1来说,最后的path结果只有1.所以下面这种找path的code是不对的。要记住上面的code
while stack or root:
if root:
stack.append(root)
if root == target:
return stack
root = root.left
else:
root = stack.pop()
root = root.right
思路2 递归
class Solution(object):
def lowestCommonAncestor(self, root, p, q):
"""
:type root: TreeNode
:type p: TreeNode
:type q: TreeNode
:rtype: TreeNode
"""
#下面的if root == None return root其实就是if root == None :return None
if root == None or root == p or root == q:
return root
# divide
left = self.lowestCommonAncestor(root.left, p, q)#返回p,q在左子树的LCA
right = self.lowestCommonAncestor(root.right, p, q)#返回p,q在右子树的LCA
# conquer # right 等于None的时候说明p和q在root.right树种没有LCA, 说明有个node不在右子树或者两个node都不在右子树。
if left and right:#两个都不为None,即在左子树有LCA,在右子树也有LCA, 那么只可能LCA 为当前的root
return root
elif left:
return left
elif right:
return right
else:
return None
自己重写findPath–postorder
def findPath(self, root, target):
stack = []
last = None
while stack or root:
if root:
stack.append(root.val)
#last = root不用写这一句
root = root.left
else:#左节点走到了None, 然后只有两条路可以走。一条就是递归stack[-1]的右子树,另一条就是回溯
peek = stack[-1]
if peek.right and last != peek.right:#第一条路,要先往右子树scan。不要先想到if last == peek.right
root = root.right
else:#第二条路,回溯,访问这个节点,更新last
if peek == target:
return stack
last = stack.pop()#回溯的时候写记录last就行。
root = None#记得写。因为在更新last的时候,用的是stack pop,会stack会缩短一个node,所以要继续回溯访问stack[-1],所以要走到回溯的点的else