235. Lowest Common Ancestor of a Binary Search Tree
## description
## 235. Lowest Common Ancestor of a Binary Search Tree
Given a binary search tree (BST), find the lowest common ancestor (LCA) node 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).”
Example 1:
1Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 8
2Output: 6
3Explanation: The LCA of nodes 2 and 8 is 6.Example 2:
1Input: root = [6,2,8,0,4,7,9,null,null,3,5], p = 2, q = 4
2Output: 2
3Explanation: The LCA of nodes 2 and 4 is 2, since a node can be a descendant of itself according to the LCA definition.Example 3:
1Input: root = [2,1], p = 2, q = 1
2Output: 2- –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.
Constraints:
## notes
### Intuition
In a BST, all nodes in the left subtree are smaller and all in the right are larger. The LCA is the first node where p and q diverge—one goes left, one goes right (or one equals the current node).
### Implementation
Solve iteratively for better space. Start at the root and traverse down. If both p and q are greater than the current value, move right. If both are smaller, move left. Otherwise, we've found the split point—this is the LCA.
### Edge-cases
The problem guarantees p and q exist in the tree, so we don't need null checks for them. One node being the ancestor of another is handled naturally—the divergence point will be that ancestor.
- –Time: O(h) — traverse at most the height of the tree
- –Space: O(1) — iterative approach uses no extra space
### Complexity
## solution
1from typing import Optional
2from lcutils import TreeNode
3
4# Definition for a binary tree node.
5# class TreeNode:
6# def __init__(self, x):
7# self.val = x
8# self.left = None
9# self.right = None
10
11class Solution:
12 def lowestCommonAncestor(self, root: Optional[TreeNode], p: Optional[TreeNode], q: Optional[TreeNode]) -> Optional[TreeNode]:
13 curr = root
14 while curr:
15 if q and p and q.val > curr.val and p.val > curr.val:
16 curr = curr.right
17 elif q and p and q.val < curr.val and p.val < curr.val:
18 curr = curr.left
19 else:
20 return curr
21
22
23
24if __name__ == "__main__":
25 # Include one-off tests here or debugging logic that can be run by running this file
26 # e.g. print(solution.two_sum([1, 2, 3, 4], 3))
27 solution = Solution()
28