-
-
Notifications
You must be signed in to change notification settings - Fork 203
Create taurus09318976.py #1668
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Create taurus09318976.py #1668
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
93 changes: 93 additions & 0 deletions
93
construct-binary-tree-from-preorder-and-inorder-traversal/taurus09318976.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,93 @@ | ||
""" | ||
문제의도: 이 문제는 트리 순회의 특성을 이해하고 재귀적 분할정복을 연습하는 문제임. | ||
-> preorder로 루트 찾고, inorder로 좌우 나누고, 재귀로 반복 | ||
- 전위 순회(preorder): 루트 -> 왼쪽 -> 오른쪽 | ||
- 중위 순회(inorder): 왼쪽 -> 루트 -> 오른쪽 | ||
|
||
해결 방법: | ||
1. preorder의 첫 번째 원소가 현재 트리의 루트임을 이용 | ||
2. inorder에서 루트의 위치를 찾아 왼쪽/오른쪽 서브트리 분할 | ||
3. preorder에서도 대응하는 부분을 분할 | ||
4. 왼쪽/오른쪽 서브트리에 대해 재귀적으로 같은 과정 반복 | ||
-> - 루트를 알면 inorder에서 왼쪽/오른쪽을 구분할 수 있음! | ||
|
||
시간복잡도: O(n²) | ||
- index() 메서드: 배열에서 값을 찾기 위해 최악의 경우 전체 배열을 순회 → O(n) | ||
- 재귀 호출 횟수: 모든 노드에 대해 한 번씩 호출 → n번 | ||
- 전체 시간복잡도: n번의 호출 × 각 호출마다 O(n) = O(n²) | ||
|
||
공간복잡도: O(n) | ||
- 재귀 호출 스택의 깊이: O(n) (편향 트리일 때) | ||
- 새로 생성하는 배열들: O(n) | ||
|
||
예시 설명 : | ||
예시1의 경우 | ||
|
||
1단계: preorder의 첫 번째는 항상 루트 | ||
[3, 9, 20, 15, 7] → 3이 루트 | ||
|
||
2단계: inorder에서 루트 위치로 좌우 분할 | ||
[9, 3, 15, 20, 7] → 3 기준으로 [9] | [15, 20, 7] | ||
- 왼쪽: [9] (인덱스 0까지) | ||
- 오른쪽: [15, 20, 7] (인덱스 2부터) | ||
|
||
3단계: 왼쪽 서브트리 크기로 preorder 분할 | ||
왼쪽 크기가 1이면 preorder에서도 1개만 가져옴 | ||
- 루트 제외: [9, 20, 15, 7] | ||
- 왼쪽 크기(1)만큼: [9] | ||
- 나머지: [20, 15, 7] | ||
|
||
4단계: 재귀적으로 같은 과정 반복 | ||
- 왼쪽: buildTree([9], [9]) → 노드 9 | ||
- 오른쪽: buildTree([20, 15, 7], [15, 20, 7]) → 서브트리 | ||
|
||
최종 결과: | ||
3 | ||
/ \ | ||
9 20 | ||
/ \ | ||
15 7 | ||
|
||
|
||
주의사항: | ||
- 배열 슬라이싱 범위 조심하기 | ||
- 빈 배열일 때 None 반환하기 | ||
- inorder에서 루트 위치 정확히 찾기 | ||
|
||
""" | ||
|
||
# Definition for a binary tree node. | ||
class TreeNode: | ||
def __init__(self, val=0, left=None, right=None): | ||
self.val = val | ||
self.left = left | ||
self.right = right | ||
|
||
|
||
class Solution: | ||
def buildTree(self, preorder, inorder): | ||
# 1. 기본 케이스: 빈 배열이면 None 반환 | ||
if not preorder or not inorder: | ||
return None | ||
|
||
# 2. preorder의 첫 번째가 루트 | ||
root_val = preorder[0] | ||
root = TreeNode(root_val) | ||
|
||
# 3. inorder에서 루트 위치 찾기 | ||
root_index = inorder.index(root_val) | ||
|
||
# 4. inorder를 루트 기준으로 분할 | ||
left_inorder = inorder[:root_index] | ||
right_inorder = inorder[root_index + 1:] | ||
|
||
# 5. preorder도 해당 크기만큼 분할 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 매번 리스트 복사 발생 → 인덱스 범위로 재귀 호출하면 성능 개선 가능 |
||
left_preorder = preorder[1:1 + len(left_inorder)] | ||
right_preorder = preorder[1 + len(left_inorder):] | ||
|
||
# 6. 재귀적으로 왼쪽과 오른쪽 서브트리 구성 | ||
root.left = self.buildTree(left_preorder, left_inorder) | ||
root.right = self.buildTree(right_preorder, right_inorder) | ||
|
||
return root | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
""" | ||
문제의 본질: "큰 트리 안에 작은 트리와 똑같은 부분이 있나?" | ||
|
||
해결 아이디어: | ||
1. 큰 트리의 모든 위치를 하나씩 확인해보기 | ||
2. 각 위치에서 "여기서 시작하는 서브트리가 찾는 트리와 완전히 같은가?" 확인하기 | ||
|
||
해결 방법: | ||
1. 큰 트리의 모든 노드를 순회 | ||
2. 각 노드에서 시작하는 서브트리가 찾는 트리와 같은지 확인 | ||
3. 같은 트리인지 확인하는 것은 별도 함수로 분리 | ||
|
||
헤결에 필요한 두 개의 함수: | ||
1. isSubtree 함수 (메인 로직): "어디서 찾을 수 있나?" (탐색 담당) | ||
- root가 None이면 False 반환 (빈 트리에선 찾을 수 없음) | ||
- 현재 위치에서 완전히 같은 트리인지 확인 | ||
- 같지 않다면 왼쪽, 오른쪽 자식에서 재귀적으로 찾기 | ||
|
||
2. isSameTree 함수 (보조 로직): "여기서 완전히 같나?" (비교 담당) | ||
- 두 트리가 완전히 같은지 확인 | ||
- 구조와 값이 모두 같아야 함 | ||
- 재귀적으로 모든 노드 비교 | ||
|
||
왜 이렇게 풀까? | ||
- 서브트리는 어느 노드에서든 시작할 수 있음 | ||
- 따라서 모든 가능한 시작점을 확인해야 함 | ||
- 각 시작점에서 완전히 같은 트리인지 확인하면 됨 | ||
|
||
기억하기 쉬운 방법: | ||
1. "모든 노드에서 시도해보기" (isSubtree) | ||
2. "완전히 같은지 확인하기" (isSameTree) | ||
이 두 가지 기능을 분리해서 생각하기! | ||
|
||
시간복잡도: O(m × n) | ||
- m: root 트리의 노드 개수 | ||
- n: subRoot 트리의 노드 개수 | ||
- 최악의 경우 root의 모든 노드에서 subRoot와 비교 | ||
|
||
공간복잡도: O(max(m, n)) | ||
- 재귀 호출 스택의 깊이는 트리의 높이와 같음 | ||
- 균형 트리라면 O(log n), 편향 트리라면 O(n) | ||
""" | ||
|
||
|
||
# 1. 먼저 TreeNode 클래스 정의 (이진 트리의 노드를 나타냄) | ||
class TreeNode: | ||
def __init__(self, val=0, left=None, right=None): | ||
self.val = val # 노드의 값 | ||
self.left = left # 왼쪽 자식 노드 | ||
self.right = right # 오른쪽 자식 노드 | ||
|
||
|
||
class Solution: | ||
# 2. 메인 함수: root 트리에서 subRoot와 같은 서브트리가 있는지 확인 | ||
def isSubtree(self, root, subRoot): | ||
|
||
# 기본 케이스 1: 큰 트리가 비어있으면 서브트리를 찾을 수 없음 | ||
if not root: | ||
return False | ||
|
||
# 기본 케이스 2: 현재 노드에서 서브트리와 완전히 일치하는지 확인 | ||
if self.isSameTree(root, subRoot): | ||
return True | ||
|
||
# 재귀 케이스: 왼쪽 서브트리 또는 오른쪽 서브트리에서 찾기 | ||
# 왼쪽 서브트리에서 찾거나 OR 오른쪽 서브트리에서 찾으면 True | ||
return (self.isSubtree(root.left, subRoot) or | ||
self.isSubtree(root.right, subRoot)) | ||
|
||
|
||
# 3. 보조 함수: 두 트리가 완전히 같은지 확인 (구조와 값 모두) | ||
def isSameTree(self, tree1, tree2): | ||
|
||
# 기본 케이스 1: 둘 다 비어있으면 같음 | ||
if not tree1 and not tree2: | ||
return True | ||
|
||
# 기본 케이스 2: 하나만 비어있으면 다름 | ||
if not tree1 or not tree2: | ||
return False | ||
|
||
# 기본 케이스 3: 현재 노드의 값이 다르면 다름 | ||
if tree1.val != tree2.val: | ||
return False | ||
|
||
# 재귀 케이스: 왼쪽 서브트리와 오른쪽 서브트리가 모두 같아야 함 | ||
# 왼쪽끼리 같고 AND 오른쪽끼리 같아야 전체가 같음 | ||
return (self.isSameTree(tree1.left, tree2.left) and | ||
self.isSameTree(tree1.right, tree2.right)) | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
O(n)이므로 전체 시간복잡도 증가 → 인덱스 맵(dict) 사전 생성 추천