Lowest Common Ancestor of a Binary Search Tree

Leetcode Daily Challenge

Posted by Haoran on July 19, 2021

Problem

Given a binary search tree (BST), find the lowest common ancestor (LCA) of two given nodes in the BST.

According to the definition of LCA on Wikipedia: “The lowest common ancestor is defined between two nodes p and q as the lowest node in T that has both p and q as descendants (where we allow a node to be a descendant of itself).”

Constraints

The number of nodes in the tree is in the range [2, 105].
-109 <= Node.val <= 109
All Node.val are unique.
p != q
p and q will exist in the BST.\

Thinking

  • Make use of the property of Binary Search Tree
    • All smaller nodes are on left, all larger nodes are on the right
    • If current node is in between two targets, then it’s the lowest common ancestor
      • To prove it, suppose it is not. So the two nodes have a same parent lower the current node. The same parent is either smaller or larger than current node, , which breaks the assumption that the the current node is in between the targets.
    • If current node is smaller than the two targets: search right
    • If current node is larger, then search left
  • Anytime if the current node value is the same with any of the target, then it is the lowest common ancestor

  • Time Complexity:
    • Best Olog(n), worst O(n), depends on the structure of the tree.


from typing import List


class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None


def lowestCommonAncestor(root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode':
    if p.val > q.val:
        temp = p
        p = q
        q = temp

    def find_lca(cur_node, p, q):
        if cur_node == p or cur_node == q:
            return cur_node

        if cur_node.val > p.val and cur_node.val < q.val:
            return cur_node

        if cur_node.val > q.val:
            return find_lca(cur_node.left, p, q)

        if cur_node.val < p.val:
            return find_lca(cur_node.right, p, q)

        return None

    return find_lca(root, p, q)


if __name__ == "__main__":
    print(lowestCommonAncestor())