|
| 1 | +# Definition for a binary tree node. |
| 2 | +# class TreeNode: |
| 3 | +# def __init__(self, val=0, left=None, right=None): |
| 4 | +# self.val = val |
| 5 | +# self.left = left |
| 6 | +# self.right = right |
| 7 | +class Solution: |
| 8 | + ''' |
| 9 | + A. 재귀 풀이 |
| 10 | + preorder와 inorder의 각각의 범위를 조정하여 트리를 생성 |
| 11 | + ''' |
| 12 | + def buildTreeA(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: |
| 13 | + def setTree(pre_left, pre_right, in_left, in_right): |
| 14 | + # 재귀 종료 조건: preorder 범위가 유효하지 않은 경우 |
| 15 | + if pre_left > pre_right: |
| 16 | + return None |
| 17 | + |
| 18 | + val = preorder[pre_left] # preorder의 현재 루트 노드 값 가져오기 |
| 19 | + mid = TreeNode(val) # 루트 노드를 먼저 생성 |
| 20 | + |
| 21 | + mid_inorder = inorder_idx_map[val] # 루트 노드의 inorder 인덱스 가져오기 |
| 22 | + left_size = mid_inorder - in_left # 왼쪽 서브트리의 크기 계산 |
| 23 | + |
| 24 | + # 왼쪽 서브트리 생성: preorder와 inorder의 범위를 왼쪽 서브트리로 조정 |
| 25 | + mid.left = setTree( |
| 26 | + pre_left + 1, pre_left + left_size, in_left, mid_inorder - 1 |
| 27 | + ) |
| 28 | + |
| 29 | + # 오른쪽 서브트리 생성: preorder와 inorder의 범위를 오른쪽 서브트리로 조정 |
| 30 | + mid.right = setTree( |
| 31 | + pre_left + left_size + 1, pre_right, mid_inorder + 1, in_right |
| 32 | + ) |
| 33 | + |
| 34 | + return mid # 현재 노드 반환 |
| 35 | + |
| 36 | + # inorder를 값 -> 인덱스 맵핑한 딕셔너리 생성 (O(n)) |
| 37 | + inorder_idx_map = {value: idx for idx, value in enumerate(inorder)} |
| 38 | + |
| 39 | + # 트리 생성 시작 (preorder와 inorder 전체 범위 사용) |
| 40 | + return setTree(0, len(preorder) - 1, 0, len(inorder) - 1) |
| 41 | + |
| 42 | + |
| 43 | + ''' |
| 44 | + # B. 재귀 풀이 + 공간 최적화 |
| 45 | + # 레퍼런스 링크의 풀이 2: https://www.algodale.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ |
| 46 | + # 특징: 순회 시마다 인덱스를 찾는 과정이 있음 |
| 47 | + ''' |
| 48 | + def buildTreeB(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: |
| 49 | + # pre: 현재 preorder에서 확인할 인덱스 |
| 50 | + # start, end: inorder에서 사용할 시작/종료 범위 |
| 51 | + def setTree(pre, start, end): |
| 52 | + # 재귀 종료 조건: 범위가 잘못되었거나 트리를 더 이상 만들 필요가 없는 경우 |
| 53 | + if not (pre < len(preorder) and start <= end): # preorder에서 확인할 인덱스가 범위에서 나감, 투 포인터가 만남 |
| 54 | + return None |
| 55 | + |
| 56 | + val = preorder[pre] # 현재 노드의 값 |
| 57 | + root = inorder.index(val) # 트리/서브트리의 루트 노드 인덱스 찾기 - SC: O(n) |
| 58 | + |
| 59 | + left = setTree(pre + 1, start, root - 1) |
| 60 | + # inorder에서 root노드의 왼쪽은 왼쪽 서브트리 |
| 61 | + # pre의 변화: 왼쪽 서브트리의 루트 노드를 찾기 위해 +1 이동 |
| 62 | + |
| 63 | + right = setTree(pre + 1 + root - start, root + 1, end) |
| 64 | + # inorder에서 root노드의 오른쪽은 오른쪽 서브트리 |
| 65 | + # pre의 변화: 오른쪽 서브트리의 루트 노드를 찾기 위해 +1 이동 + (root - start) 👈 왼쪽 서브트리의 크기 만큼 더 이동 |
| 66 | + |
| 67 | + return TreeNode(preorder[pre], left, right) # 트리 노드 생성 |
| 68 | + |
| 69 | + # preorder 최초 인덱스 = 루트 노드(0), inorder의 처음(0)과 끝(len(inorder) - 1) 인덱스 |
| 70 | + return setTree(0, 0, len(inorder) - 1) |
| 71 | + |
| 72 | + ''' |
| 73 | + C. 재귀 풀이 + 시간 최적화 |
| 74 | + 레퍼런스 링크의 풀이 3: https://www.algodale.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ |
| 75 | + 특징: A에서 preorder를 찾는 O(n) 과정을 해시 테이블을 사용하여 O(1)로 최적화 |
| 76 | + ''' |
| 77 | + def buildTreeC(self, preorder: List[int], inorder: List[int]) -> Optional[TreeNode]: |
| 78 | + # enumerate: 인덱스와 값을 동시에 반환 |
| 79 | + # inorder를 val -> idx로 매핑한 딕셔너리 생성 |
| 80 | + inorder_index_map = {val: idx for idx, val in enumerate(inorder)} |
| 81 | + # preorder를 순회하기 위한 iterator 객체 생성 |
| 82 | + pre_iter = iter(preorder) |
| 83 | + |
| 84 | + def setTree(start, end): |
| 85 | + if start > end: # 재귀 종료 조건: 범위가 잘못되었거나 트리를 더 이상 만들 필요가 없는 경우 |
| 86 | + return None |
| 87 | + |
| 88 | + root_val = next(pre_iter) # 현재 노드의 값, 매 순회마다 다음 preorder 노드(root)의 값을 가져옴 |
| 89 | + root = inorder_index_map[root_val] # 트리/서브트리의 루트 노드 인덱스를 O(1) 시간으로 찾기 |
| 90 | + |
| 91 | + left = setTree(start, root - 1) # 왼쪽 서브트리 |
| 92 | + right = setTree(root + 1, end) # 오른쪽 서브트리 |
| 93 | + return TreeNode(root_val, left, right) # 트리 노드 생성 |
| 94 | + |
| 95 | + return setTree(0, len(inorder) - 1) # inorder의 처음(0)과 끝(len(inorder) - 1) 인덱스 |
0 commit comments