leetcode -- Lowest Common Ancestor of a Binary Tree -- 重点

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

你可能感兴趣的:(LeetCode)