|
| 1 | +''' |
| 2 | +# 235. Lowest Common Ancestor of a Binary Search Tree |
| 3 | +
|
| 4 | +## 기본적인 LCA 찾기 문제이다. |
| 5 | +- LCA는 BST에서 주어진 두 노드의 최저 공통 조상이다. |
| 6 | +- 두 노드를 descendants로 가진 노드이며, 두 노드도 포함된다. |
| 7 | +
|
| 8 | +### LCA와 이진 탐색 트리 BST, 일반 이진트리 BT |
| 9 | +BST는 부모의 정렬 조건이 있고, BT는 부모의 정렬 조건이 없다. |
| 10 | +BST는 이진 탐색을 진행하지만, BT는 구조적 단서가 없으므로 모든 경로를 탐색해야 한다.(Post-order DFS) |
| 11 | +따라서 BT의 시간 복잡도는 O(N)이다. |
| 12 | +
|
| 13 | +- BT의 LCA 찾기 문제: [236. Lowest Common Ancestor of a Binary Tree](https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-tree/) |
| 14 | +
|
| 15 | +## Approach |
| 16 | +- p, q가 현재 노드보다 작으면, 왼쪽으로 이동 |
| 17 | +- p, q가 현재 노드보다 크면, 오른쪽으로 이동 |
| 18 | +- p, q가 현재 노드에서 양쪽으로 분리되어 나간다면, 현재 노드가 LCA이다. |
| 19 | +
|
| 20 | +### 재귀와 반복문 |
| 21 | +재귀는 함수 호출마다 call stack 프레임이 생긴다.(push/pop) |
| 22 | +오버헤드가 발생하여 공간 복잡도가 O(H)이다. |
| 23 | +인터프리터는 특성상 재귀 성능 호출이 비교적 좋지 않다. |
| 24 | +또한 트리가 매우 깊어서 H가 큰 경우, Stack Overflow 발생 가능성이 있다. |
| 25 | +
|
| 26 | +## 시간 & 공간 복잡도 |
| 27 | +
|
| 28 | +``` |
| 29 | +TC: O(H) |
| 30 | +SC: O(1) |
| 31 | +``` |
| 32 | +
|
| 33 | +### TC is O(H): |
| 34 | +- 트리의 높이만큼 반복문을 돌리므로, O(H)이다. |
| 35 | +
|
| 36 | +### SC is O(1): |
| 37 | +- 추가 공간 사용 없음 |
| 38 | +- 만약 재귀로 풀이한다면, 함수 호출마다 콜스택 공간이 생기므로 O(H)이다. |
| 39 | +''' |
| 40 | +class Solution: |
| 41 | + ''' |
| 42 | + 반복문 Top-down |
| 43 | + TC: O(H) |
| 44 | + SC: O(1) |
| 45 | + ''' |
| 46 | + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': |
| 47 | + while root: |
| 48 | + if p.val < root.val and q.val < root.val: |
| 49 | + root = root.left |
| 50 | + elif p.val > root.val and q.val > root.val: |
| 51 | + root = root.right |
| 52 | + else: |
| 53 | + return root |
| 54 | + ''' |
| 55 | + 재귀 Bottom-up |
| 56 | + TC: O(H) |
| 57 | + SC: O(H) |
| 58 | + ''' |
| 59 | + def lowestCommonAncestorBottomUp(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': |
| 60 | + if p.val < root.val and q.val < root.val: |
| 61 | + return self.lowestCommonAncestor(root.left, p, q) |
| 62 | + elif p.val > root.val and q.val > root.val: |
| 63 | + return self.lowestCommonAncestor(root.right, p, q) |
| 64 | + else: |
| 65 | + return root |
0 commit comments