트리의 순회 방법의 특징들을 알면 풀 수 있는 문제. 특히 순회 별 트리의 root를 찾는 방법이 중요하다.
left - root - right
순서로 순회. root
를 중간에 순회한다.root - left - right
순서로 순회. root
를 가장 처음에 순회한다.left - right - root
순서로 순회. root
를 가장 마지막에 순회한다.
위와 같은 트리를 중위순회하는 경우와 후위순회하는 경우의 결과는 다음과 같다.
4 2 1 7 5 3 6
4 2 7 5 6 3 1
이때 root
를 찾는 가장 간단한 방법은 후위순회의 마지막 숫자가 root
라는 점을 이용하는 것이다. 따라서 위 경우의 root가 1
이라는 것을 알 수 있다. 이 값을 결과를 저장할 배열에 append
한다.
다음으로는 중위순회에서 root
의 위치를 찾는다. 그 점을 기준으로 이전 값들이 left
, 이후 값들이 right
이다. 4 2 1 7 5 3 6
에서 1
의 이전값인 4 2
가 left
고 7 5 3 6
이 right
이다.
4 2
가 left
고 7 5 3 6
이 right
인 점을 이용해 후위순회 결과를 둘로 나눈다. left
의 원소가 2개이고 right
의 원소가 4개이므로 후위순회의 결과를 앞 2개, 뒤 4개로 나눈다.
left
로 1단계부터 다시, right
로 1단계부터 다시한다. 트리의 left
, right
역시 트리이므로, 큰 문제가 작은 두 문제로 나뉘는 분할정복의 형태임을 알 수 있다.
import sys
input = sys.stdin.readline
sys.setrecursionlimit(100005)
n = int(input())
inorder_arr = list(map(int, input().split()))
inorder_idx = {inorder_arr[i]: i for i in range(n)}
postorder_arr = list(map(int, input().split()))
answer = []
def preorder(in_start: int = 0, in_end: int = n - 1, post_start: int = 0, post_end: int = n - 1):
if in_start > in_end:
return
root = postorder_arr[post_end]
answer.append(root)
if in_start == in_end:
return
in_root_idx: int = inorder_idx[root]
left_len = in_root_idx - in_start
preorder(in_start, in_root_idx - 1, post_start, post_start + left_len - 1)
preorder(in_root_idx + 1, in_end, post_start + left_len, post_end - 1)
def main():
preorder()
print(*answer)
if __name__ == '__main__':
main()