December 05, 2018
| 시간 제한 | 메모리 제한 |
|---|---|
| 5초 | 128MB |
n개의 정점을 갖는 이진 트리의 정점에 1부터 n까지의 번호가 중복 없이 매겨져 있다.
이와 같은 이진 트리의 인오더와 포스트오더가 주어졌을 때,
프리오더를 구하는 프로그램을 작성하시오.
첫째 줄에 n(1 ≤ n ≤ 100,000)이 주어진다.
다음 줄에는 인오더를 나타내는 n개의 자연수가 주어지고,
그 다음 줄에는 같은 식으로 포스트오더가 주어진다.
첫째 줄에 프리오더를 출력한다.
3
1 2 3
1 3 22 1 3백준의 예제는 너무 쉽게 끝나므로 다음의 예로 설명하겠습니다.
Inorder Traversal
| 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| 1 | 2 | 5 | 3 | 6 | 4 |
Postorder Traversal
| 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| 1 | 5 | 2 | 6 | 4 | 3 |
Preorder Traversal
| 0 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| 3 | 2 | 1 | 5 | 4 | 6 |
후위 순회의 마지막 출력은 루트 노드다.
전체 배열 0 ~ 5 번쨰의 5번째의 3은 전체 트리의 루트 노드
왼쪽 서브 트리 0 ~ 2 번째의 2번째의 2는 왼쪽 서브트리의 루트노드
오른쪽 서브 트리 3 ~ 4 번째의 4번째의 4는 오른쪽 서브트리의 루트노드
root = postorder[postorder_end]왼쪽 서브 트리의 사이즈는 다음의 공식으로 얻을 수 있다.
오른쪽 서브 트리의 사이즈는 자연스럽게 얻을 수 있다.
inorder_root = inposition[root]
left_size = inorder_root - inorder_start따라서 중위 순회의 루트 노드 인덱스를 기준으로 리스트의 왼쪽은
왼쪽 서브 트리가 되고 리스트의 오른쪽은 오른쪽 서브트리가 된다.
이를 위해서 중위 순회의 순회 순서인 inposition 배열을 하나 만들어야 한다.
inposition = [0] * (max(inorder) + 1)
for i, v in enumerate(inorder):
inposition[v] = i따라서 다음과 같은 inposition 리스트가 하나 생성될 것이다.
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |
|---|---|---|---|---|---|---|
| 0 | 0 | 1 | 3 | 5 | 2 | 4 |
이제 본격적으로 함수를 구현해볼 차례다.
def get_preorder(inorder_start, inorder_end, postorder_start, postorder_end):해당 함수를 재귀적으로 호출하면서 왼쪽 서브트리, 오른쪽 서브트리
순서로 방문하면서 루트 노드를 출력해주면 된다.
루트 노드
| index | 3 | index | 5 |
|---|---|---|---|
| inorder | 3 | postorder | 3 |
왼쪽 서브 트리
| index | 0 | 1 | 2 | index | 0 | 1 | 2 |
|---|---|---|---|---|---|---|---|
| inorder | 1 | 2 | 5 | postorder | 1 | 5 | 2 |
오른쪽 서브 트리
| index | 4 | 5 | index | 3 | 4 |
|---|---|---|---|---|---|
| inorder | 6 | 4 | postorder | 6 | 4 |
다음과 같은 과정을 재귀적으로 호출하면 문제가 해결된다.
postorder_start > postorder_endinorder_start > inorder_enddef get_preorder(inorder_start, inorder_end, postorder_start, postorder_end):
if postorder_start > postorder_end:
return
if inorder_start > inorder_end:
return
root = postorder[postorder_end]
print(root, end=" ")
inorder_root = inposition[root]
left_size = inorder_root - inorder_start
get_preorder(inorder_start, inorder_root - 1,
postorder_start, postorder_start + left_size - 1)
get_preorder(inorder_root + 1, inorder_end,
postorder_start + left_size, postorder_end - 1)import sys
sys.recursionlimit(10 ** 6)
n = int(sys.stdin.readline())
inorder = list(map(int, sys.stdin.readline().split(' ')))
postorder = list(map(int, sys.stdin.readline().split(' ')))
inposition = [0] * (max(inorder) + 1)
for i, v in enumerate(inorder):
inposition[v] = i
get_preorder(0, n - 1, 0, n - 1)
3 ❯ 2 ❯ 1 ❯ 5 ❯ 4 ❯ 6 의 순서로 출력이 된다.
코드를 보기만 하는 것 보다 직접 진행 순서를 한 번씩
그려보면서 이해해보는 것이 좋을 것이다😁😁.
✅ 코드는 [여기]에서 확인할 수 있다.
재귀 함수를 사용한 풀이 방법이라 속도가 좋지않다.
시간 초과가 생긴다면 PyPy3로 제출해 보길 바란다.