Skip to content

Commit 53ce7c7

Browse files
Merge pull request #1668 from taurus09318976/main
Create taurus09318976.py
2 parents dfa1ccd + 52ad3d1 commit 53ce7c7

File tree

2 files changed

+183
-0
lines changed

2 files changed

+183
-0
lines changed
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
"""
2+
문제의도: 이 문제는 트리 순회의 특성을 이해하고 재귀적 분할정복을 연습하는 문제임.
3+
-> preorder로 루트 찾고, inorder로 좌우 나누고, 재귀로 반복
4+
- 전위 순회(preorder): 루트 -> 왼쪽 -> 오른쪽
5+
- 중위 순회(inorder): 왼쪽 -> 루트 -> 오른쪽
6+
7+
해결 방법:
8+
1. preorder의 첫 번째 원소가 현재 트리의 루트임을 이용
9+
2. inorder에서 루트의 위치를 찾아 왼쪽/오른쪽 서브트리 분할
10+
3. preorder에서도 대응하는 부분을 분할
11+
4. 왼쪽/오른쪽 서브트리에 대해 재귀적으로 같은 과정 반복
12+
-> - 루트를 알면 inorder에서 왼쪽/오른쪽을 구분할 수 있음!
13+
14+
시간복잡도: O(n²)
15+
- index() 메서드: 배열에서 값을 찾기 위해 최악의 경우 전체 배열을 순회 → O(n)
16+
- 재귀 호출 횟수: 모든 노드에 대해 한 번씩 호출 → n번
17+
- 전체 시간복잡도: n번의 호출 × 각 호출마다 O(n) = O(n²)
18+
19+
공간복잡도: O(n)
20+
- 재귀 호출 스택의 깊이: O(n) (편향 트리일 때)
21+
- 새로 생성하는 배열들: O(n)
22+
23+
예시 설명 :
24+
예시1의 경우
25+
26+
1단계: preorder의 첫 번째는 항상 루트
27+
[3, 9, 20, 15, 7] → 3이 루트
28+
29+
2단계: inorder에서 루트 위치로 좌우 분할
30+
[9, 3, 15, 20, 7] → 3 기준으로 [9] | [15, 20, 7]
31+
- 왼쪽: [9] (인덱스 0까지)
32+
- 오른쪽: [15, 20, 7] (인덱스 2부터)
33+
34+
3단계: 왼쪽 서브트리 크기로 preorder 분할
35+
왼쪽 크기가 1이면 preorder에서도 1개만 가져옴
36+
- 루트 제외: [9, 20, 15, 7]
37+
- 왼쪽 크기(1)만큼: [9]
38+
- 나머지: [20, 15, 7]
39+
40+
4단계: 재귀적으로 같은 과정 반복
41+
- 왼쪽: buildTree([9], [9]) → 노드 9
42+
- 오른쪽: buildTree([20, 15, 7], [15, 20, 7]) → 서브트리
43+
44+
최종 결과:
45+
3
46+
/ \
47+
9 20
48+
/ \
49+
15 7
50+
51+
52+
주의사항:
53+
- 배열 슬라이싱 범위 조심하기
54+
- 빈 배열일 때 None 반환하기
55+
- inorder에서 루트 위치 정확히 찾기
56+
57+
"""
58+
59+
# Definition for a binary tree node.
60+
class TreeNode:
61+
def __init__(self, val=0, left=None, right=None):
62+
self.val = val
63+
self.left = left
64+
self.right = right
65+
66+
67+
class Solution:
68+
def buildTree(self, preorder, inorder):
69+
# 1. 기본 케이스: 빈 배열이면 None 반환
70+
if not preorder or not inorder:
71+
return None
72+
73+
# 2. preorder의 첫 번째가 루트
74+
root_val = preorder[0]
75+
root = TreeNode(root_val)
76+
77+
# 3. inorder에서 루트 위치 찾기
78+
root_index = inorder.index(root_val)
79+
80+
# 4. inorder를 루트 기준으로 분할
81+
left_inorder = inorder[:root_index]
82+
right_inorder = inorder[root_index + 1:]
83+
84+
# 5. preorder도 해당 크기만큼 분할
85+
left_preorder = preorder[1:1 + len(left_inorder)]
86+
right_preorder = preorder[1 + len(left_inorder):]
87+
88+
# 6. 재귀적으로 왼쪽과 오른쪽 서브트리 구성
89+
root.left = self.buildTree(left_preorder, left_inorder)
90+
root.right = self.buildTree(right_preorder, right_inorder)
91+
92+
return root
93+
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
"""
2+
문제의 본질: "큰 트리 안에 작은 트리와 똑같은 부분이 있나?"
3+
4+
해결 아이디어:
5+
1. 큰 트리의 모든 위치를 하나씩 확인해보기
6+
2. 각 위치에서 "여기서 시작하는 서브트리가 찾는 트리와 완전히 같은가?" 확인하기
7+
8+
해결 방법:
9+
1. 큰 트리의 모든 노드를 순회
10+
2. 각 노드에서 시작하는 서브트리가 찾는 트리와 같은지 확인
11+
3. 같은 트리인지 확인하는 것은 별도 함수로 분리
12+
13+
헤결에 필요한 두 개의 함수:
14+
1. isSubtree 함수 (메인 로직): "어디서 찾을 수 있나?" (탐색 담당)
15+
- root가 None이면 False 반환 (빈 트리에선 찾을 수 없음)
16+
- 현재 위치에서 완전히 같은 트리인지 확인
17+
- 같지 않다면 왼쪽, 오른쪽 자식에서 재귀적으로 찾기
18+
19+
2. isSameTree 함수 (보조 로직): "여기서 완전히 같나?" (비교 담당)
20+
- 두 트리가 완전히 같은지 확인
21+
- 구조와 값이 모두 같아야 함
22+
- 재귀적으로 모든 노드 비교
23+
24+
왜 이렇게 풀까?
25+
- 서브트리는 어느 노드에서든 시작할 수 있음
26+
- 따라서 모든 가능한 시작점을 확인해야 함
27+
- 각 시작점에서 완전히 같은 트리인지 확인하면 됨
28+
29+
기억하기 쉬운 방법:
30+
1. "모든 노드에서 시도해보기" (isSubtree)
31+
2. "완전히 같은지 확인하기" (isSameTree)
32+
이 두 가지 기능을 분리해서 생각하기!
33+
34+
시간복잡도: O(m × n)
35+
- m: root 트리의 노드 개수
36+
- n: subRoot 트리의 노드 개수
37+
- 최악의 경우 root의 모든 노드에서 subRoot와 비교
38+
39+
공간복잡도: O(max(m, n))
40+
- 재귀 호출 스택의 깊이는 트리의 높이와 같음
41+
- 균형 트리라면 O(log n), 편향 트리라면 O(n)
42+
"""
43+
44+
45+
# 1. 먼저 TreeNode 클래스 정의 (이진 트리의 노드를 나타냄)
46+
class TreeNode:
47+
def __init__(self, val=0, left=None, right=None):
48+
self.val = val # 노드의 값
49+
self.left = left # 왼쪽 자식 노드
50+
self.right = right # 오른쪽 자식 노드
51+
52+
53+
class Solution:
54+
# 2. 메인 함수: root 트리에서 subRoot와 같은 서브트리가 있는지 확인
55+
def isSubtree(self, root, subRoot):
56+
57+
# 기본 케이스 1: 큰 트리가 비어있으면 서브트리를 찾을 수 없음
58+
if not root:
59+
return False
60+
61+
# 기본 케이스 2: 현재 노드에서 서브트리와 완전히 일치하는지 확인
62+
if self.isSameTree(root, subRoot):
63+
return True
64+
65+
# 재귀 케이스: 왼쪽 서브트리 또는 오른쪽 서브트리에서 찾기
66+
# 왼쪽 서브트리에서 찾거나 OR 오른쪽 서브트리에서 찾으면 True
67+
return (self.isSubtree(root.left, subRoot) or
68+
self.isSubtree(root.right, subRoot))
69+
70+
71+
# 3. 보조 함수: 두 트리가 완전히 같은지 확인 (구조와 값 모두)
72+
def isSameTree(self, tree1, tree2):
73+
74+
# 기본 케이스 1: 둘 다 비어있으면 같음
75+
if not tree1 and not tree2:
76+
return True
77+
78+
# 기본 케이스 2: 하나만 비어있으면 다름
79+
if not tree1 or not tree2:
80+
return False
81+
82+
# 기본 케이스 3: 현재 노드의 값이 다르면 다름
83+
if tree1.val != tree2.val:
84+
return False
85+
86+
# 재귀 케이스: 왼쪽 서브트리와 오른쪽 서브트리가 모두 같아야 함
87+
# 왼쪽끼리 같고 AND 오른쪽끼리 같아야 전체가 같음
88+
return (self.isSameTree(tree1.left, tree2.left) and
89+
self.isSameTree(tree1.right, tree2.right))
90+

0 commit comments

Comments
 (0)