Lowest Common Ancestor of a BST
Given a BST as a level-order array and two node values p and q, find their lowest common ancestor (LCA). The LCA is the deepest node that is an ancestor of both p and q (a node can be its own ancestor).
Example:
6,2,8,0,4,7,9,null,null,3,5 2 8
6
- The given level-order array represents a Binary Search Tree (BST) where for each node, all elements in its left subtree are less than the node, and all elements in its right subtree are greater than the node.
- The BST is constructed as follows:
- Root: 6
- Left subtree: 2 (root), 0 (left child), 4 (right child), 3 (left child of 4), 5 (right child of 4)
- Right subtree: 8 (root), 7 (left child), 9 (right child)
- To find the LCA of nodes
p = 2andq = 8, we observe that2is in the left subtree of the root (6) and8is in the right subtree of the root (6), meaning the root (6) is the first common ancestor of bothpandqand, being the root, the deepest such ancestor. - Since
6is the root and the first common ancestor ofpandq, it is their lowest common ancestor (LCA).
Constraints:
- 2 <= number of nodes <= 10^5
- All values unique
- p != q, both exist in tree
Background Knowledge
The problem involves finding the Lowest Common Ancestor (LCA) of two nodes in a Binary Search Tree (BST). A BST is a tree data structure where each node has at most two children (i.e., left child and right child) and each node represents a value. The key property of a BST is that for any given node, all elements in its left subtree are less than the node, and all elements in its right subtree are greater than the node. This property allows for efficient searching, insertion, and deletion of nodes.
To understand the concept of LCA, consider a tree where two nodes p and q are given. The LCA of p and q is the deepest node that is an ancestor of both p and q. In other words, it is the node farthest from the root that is still a common ancestor of both p and q. In the context of a BST, the LCA can be found by traversing the tree and leveraging its ordered property.
The problem provides the BST as a level-order array, which means the nodes are arranged in a way that all nodes at a given depth level are visited before moving on to the next level. This representation can be useful for traversing the tree level by level. Understanding how to traverse a tree, both depth-first and breadth-first, is essential for solving this problem.
Algorithm/Approach
The general approach to solving this type of problem involves tree traversal and ancestor identification. Given the BST property, one can leverage the fact that all elements to the left of a node are smaller, and all elements to the right are larger. This property can guide the traversal towards finding the LCA of two given nodes. The algorithm may involve recursively or iteratively traversing the tree, comparing node values to determine the path towards the LCA.
Step-by-Step Strategy
To implement the solution:
- Construct the BST from the given level-order array, if necessary.
- Identify the nodes p and q within the BST.
- Traverse the BST to find the LCA, leveraging the BST property to guide the traversal.
- Compare node values to determine whether to move left or right in the tree.
- Stop when the LCA is found, which will be the node that is an ancestor of both p and q and is farthest from the root.
Common Pitfalls
- Failing to leverage the BST property, leading to inefficient traversal.
- Incorrectly identifying the LCA, especially in cases where p or q is the root or when one is a descendant of the other.
- Not handling edge cases, such as when p or q is not found in the tree.
Time & Space Complexity
The expected time complexity for finding the LCA in a BST is O(h), where h is the height of the tree, because in the worst case, one might have to traverse from the root to the deepest leaf. In a balanced BST, h=log(n), where n is the number of nodes, leading to a time complexity of O(logn). However, in the worst case (an unbalanced tree), h=n, resulting in a time complexity of O(n). The space complexity depends on the implementation, but for a recursive approach, it would be O(h) due to the recursion stack.