[백준 2263] 트리의 순회 (C#, C++) - soo:bak
작성일 :
문제 링크
설명
이진 트리의 순회 결과가 주어지는 상황에서, 노드의 개수 n (1 ≤ n ≤ 100,000)과 인오더(중위 순회) 결과, 포스트오더(후위 순회) 결과가 주어질 때, 프리오더(전위 순회) 결과를 구하는 문제입니다.
세 가지 순회 방식은 다음과 같습니다:
- 인오더(중위): 왼쪽 서브트리 → 루트 → 오른쪽 서브트리
- 포스트오더(후위): 왼쪽 서브트리 → 오른쪽 서브트리 → 루트
- 프리오더(전위): 루트 → 왼쪽 서브트리 → 오른쪽 서브트리
포스트오더의 마지막 원소가 루트이며, 인오더에서 루트의 위치를 찾으면 좌우 서브트리를 구분할 수 있습니다. 이 성질을 이용하여 재귀적으로 프리오더를 복원합니다.
접근법
분할 정복과 재귀를 사용하여 인오더와 포스트오더로부터 프리오더를 복원합니다.
먼저 인오더 배열에서 각 값의 인덱스를 저장하는 매핑을 만듭니다. 이렇게 하면 루트 노드를 찾았을 때 인오더에서의 위치를 O(1)에 찾을 수 있습니다.
재귀 함수를 정의합니다. 함수는 인오더의 구간 [inL, inR]과 포스트오더의 구간 [postL, postR]을 받습니다. 포스트오더의 마지막 원소 postorder[postR]이 현재 서브트리의 루트입니다. 이 루트를 프리오더 순서대로 먼저 출력합니다.
이후, 인오더에서 루트의 위치를 찾습니다. 루트의 인덱스를 idx라 하면, 왼쪽 서브트리의 크기는 idx - inL입니다. 이 크기를 이용하여 인오더와 포스트오더를 각각 왼쪽 서브트리와 오른쪽 서브트리 구간으로 나눕니다.
왼쪽 서브트리에 대해 재귀 호출을 먼저 수행하고, 그 다음 오른쪽 서브트리에 대해 재귀 호출합니다. 이렇게 하면 프리오더 순서(루트 → 왼쪽 → 오른쪽)로 출력됩니다.
예를 들어, 인오더가 [4, 2, 5, 1, 6, 3, 7], 포스트오더가 [4, 5, 2, 6, 7, 3, 1]인 경우:
포스트오더의 마지막 원소 1이 루트입니다. 인오더에서 1의 위치는 인덱스 3이므로, 왼쪽 서브트리는 [4, 2, 5] (크기 3), 오른쪽 서브트리는 [6, 3, 7]입니다.
왼쪽 서브트리의 포스트오더는 [4, 5, 2]이고 마지막 원소 2가 루트입니다. 이를 재귀적으로 반복하면 프리오더는 1 → 2 → 4 → 5 → 3 → 6 → 7 순서로 출력됩니다.
각 노드를 한 번씩만 방문하므로 시간 복잡도는 O(n)입니다.
Code
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
using System;
using System.Text;
namespace Solution {
class Program {
static int[] inorder, postorder, pos;
static StringBuilder sb = new StringBuilder();
static void Solve(int inL, int inR, int postL, int postR) {
if (inL > inR || postL > postR)
return;
var root = postorder[postR];
sb.Append(root).Append(' ');
var idx = pos[root];
var leftSize = idx - inL;
Solve(inL, idx - 1, postL, postL + leftSize - 1);
Solve(idx + 1, inR, postL + leftSize, postR - 1);
}
static void Main(string[] args) {
var n = int.Parse(Console.ReadLine()!);
inorder = Array.ConvertAll(Console.ReadLine()!.Split(), int.Parse);
postorder = Array.ConvertAll(Console.ReadLine()!.Split(), int.Parse);
pos = new int[n + 1];
for (var i = 0; i < n; i++)
pos[inorder[i]] = i;
Solve(0, n - 1, 0, n - 1);
Console.WriteLine(sb.ToString().TrimEnd());
}
}
}
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <bits/stdc++.h>
using namespace std;
vector<int> inorder, postorder, posIdx;
ostringstream out;
void solve(int inL, int inR, int postL, int postR) {
if (inL > inR || postL > postR)
return;
int root = postorder[postR];
out << root << ' ';
int idx = posIdx[root];
int leftSize = idx - inL;
solve(inL, idx - 1, postL, postL + leftSize - 1);
solve(idx + 1, inR, postL + leftSize, postR - 1);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n; cin >> n;
inorder.resize(n);
postorder.resize(n);
posIdx.assign(n + 1, 0);
for (int i = 0; i < n; i++)
cin >> inorder[i];
for (int i = 0; i < n; i++)
cin >> postorder[i];
for (int i = 0; i < n; i++)
posIdx[inorder[i]] = i;
solve(0, n - 1, 0, n - 1);
string res = out.str();
if (!res.empty() && res.back() == ' ')
res.pop_back();
cout << res << "\n";
return 0;
}