728x90
반응형
문제 요약
- 알고리즘 분류: 트리, 트리 탐색
- 난이도: Gold4
- 문제내용:
- 이진 검색 트리는 다음과 같은 세 가지 조건을 만족하는 이진 트리이다.
- 노드의 왼쪽 서브트리에 있는 모든 노드의 키는 노드의 키보다 작다.
- 노드의 오른쪽 서브트리에 있는 모든 노드의 키는 노드의 키보다 크다.
- 왼쪽, 오른쪽 서브트리도 이진 검색 트리이다.
- 위 트리에서 전위 순회 한것을 후위 순회한 결과를 출력하여라
- 이진 검색 트리는 다음과 같은 세 가지 조건을 만족하는 이진 트리이다.
- 사이트: https://www.acmicpc.net/problem/5639
문제풀이
이번에는 문제 유형은 트리 탐색에 관련 문제이다. 트리에 관한 자세한 내용은 여기에서 보면된다.
문제 접근방법
이 문제의 핵심은 전위 순회 결과만 가지고 후위 순회 결과를 어떻게 구하느냐는 것입니다. 아래 와 같이 처음부터 집어 넣는 식으로 만들면 시간 초과로 나올 것입니다.
import sys
sys.setrecursionlimit(10 ** 9)
input = sys.stdin.readline
def post_order(node):
if tree[node][0]:
post_order(tree[node][0])
if tree[node][1]:
post_order(tree[node][1])
print(node)
root = int(input())
tree = {root: [0, 0]}
while True:
try:
node = root
N = int(input())
tree[N] = [0, 0]
while node != 0:
if N < node:
after_node = tree[node][0]
index = 0
else:
after_node = tree[node][1]
index = 1
if after_node == 0:
tree[node][index] = N
break
node = after_node
except:
break
post_order(root)
그래서 전위 순회 특성을 이용해서 후위 순위를 출력 하는 식으로 구현 해야지 시간 초과 이슈가 안 일어 날 것입니다.
전위 순회의 특성상 가장 먼저 나오는 값이 루트 노드입니다. 이진 검색 트리의 특성을 활용하면, 루트 노드보다 큰 첫 번째 값이 나오는 위치부터는 오른쪽 서브트리가 시작됩니다. 이를 이용해 트리를 아래와 같은 구조로 탐색 할수 있습니다.
알고리즘 단계:
- 전위 순회 결과의 첫 번째 값은 현재 서브트리의 루트입니다.
- 루트보다 큰 첫 번째 값을 찾습니다. 이 값부터 오른쪽 서브트리가 시작됩니다.
- 루트 다음부터 오른쪽 서브트리 시작 전까지가 왼쪽 서브트리입니다.
- 왼쪽 서브트리와 오른쪽 서브트리에 대해 재귀적으로 같은 과정을 수행합니다.
- 후위 순회 순서(왼쪽-오른쪽-루트)로 값을 출력합니다.
마무리
이 문제는 이진 검색 트리의 특성과 트리 순회 방법에 대한 이해를 필요로 합니다. 재귀적으로 문제를 해결하는 방식으로, 전위 순회 결과만으로 원래 트리 구조를 유추하고 후위 순회 결과를 생성할 수 있습니다.
핵심 통찰은 이진 검색 트리에서 루트보다 큰 값이 처음 나타나는 위치가 오른쪽 서브트리의 시작이라는 점입니다. 이를 활용하여 트리를 분할 정복 방식으로 처리하면 효율적으로 문제를 해결할 수 있습니다.
이 문제를 통해 트리 자료구조와 재귀 알고리즘에 대한 이해를 깊게 할 수 있습니다.
Code
Python
import sys
sys.setrecursionlimit(10 ** 9)
input = sys.stdin.readline
"""
전위 순회 결과로부터 후위 순회 결과를 생성하는 함수
root: 현재 서브트리의 루트 노드 인덱스
end: 현재 서브트리의 마지막 노드 인덱스
"""
def post_order(root, end):
# 기저 조건: 유효하지 않은 범위면 종료
if root > end:
return
start = root + 1 # 루트 다음 노드(왼쪽 서브트리의 시작)
node = nodes[root] # 현재 서브트리의 루트 값
# 오른쪽 서브트리의 시작점(mid)을 찾음
# 루트 값보다 큰 첫 번째 노드가 오른쪽 서브트리의 시작
for index in range(start, end + 1):
if node < nodes[index]:
mid = index
break
else:
# 모든 값이 루트보다 작거나 같으면 오른쪽 서브트리는 없음
mid = end + 1
# 왼쪽 서브트리 후위 순회 (start부터 mid-1까지)
post_order(start, mid - 1)
# 오른쪽 서브트리 후위 순회 (mid부터 end까지)
post_order(mid, end)
# 현재 노드 출력 (후위 순회에서는 루트가 마지막에 방문됨)
print(node)
# 노드 값을 저장할 리스트
nodes = []
# EOF(파일 끝)까지 입력 받기
while True:
try:
N = int(input())
nodes.append(N)
except:
# 입력이 더 이상 없거나 오류 발생시 입력 종료
break
# 전체 트리에 대해 후위 순회 수행 (0부터 마지막 인덱스까지)
post_order(0, len(nodes) - 1)
Java
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
public class Main {
static List<Integer> nodes; // 노드 값을 저장할 리스트
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader((System.in)));
nodes = new ArrayList<>();
nodes.add(Integer.valueOf(br.readLine()));
String line;
while ((line = br.readLine()) != null && !line.isEmpty()) {
nodes.add(Integer.valueOf(line));
}
// 전체 트리에 대해 후위 순회 수행 (0부터 마지막 인덱스까지)
postOrder(0, nodes.size() - 1);
}
/*
* 전위 순회 결과로부터 후위 순회 결과를 생성하는 함수
* root: 현재 서브트리의 루트 노드 인덱스
* end: 현재 서브트리의 마지막 노드 인덱스
*/
static void postOrder(int root, int end){
// 기저 조건: 유효하지 않은 범위면 종료
if(root > end){
return;
}
int start = root + 1; // 루트 다음 노드(왼쪽 서브트리의 시작)
int node = nodes.get(root); // 현재 서브트리의 루트 값
int mid = start;
// 오른쪽 서브트리의 시작점(mid)을 찾음
// 루트 값보다 큰 첫 번째 노드가 오른쪽 서브트리의 시작
while(mid <= end){
if(node < nodes.get(mid)){
break;
}
mid++;
}
// 왼쪽 서브트리 후위 순회 (start부터 mid-1까지)
postOrder(start, mid - 1);
// 오른쪽 서브트리 후위 순회 (mid부터 end까지)
postOrder(mid, end);
// 현재 노드 출력 (후위 순회에서는 루트가 마지막에 방문됨)
System.out.println(node);
}
}
Javascript
var input = require('fs').readFileSync('/dev/stdin').toString().trim().split('\n');
/*
* 전위 순회 결과로부터 후위 순회 결과를 생성하는 함수
* root: 현재 서브트리의 루트 노드 인덱스
* end: 현재 서브트리의 마지막 노드 인덱스
*/
function postOrder(root, end){
// 기저 조건: 유효하지 않은 범위면 종료
if(root > end){
return;
}
const start = root + 1; // 루트 다음 노드(왼쪽 서브트리의 시작)
const node = nodes[root]; // 현재 서브트리의 루트 값
let mid = start;
// 오른쪽 서브트리의 시작점(mid)을 찾음
// 루트 값보다 큰 첫 번째 노드가 오른쪽 서브트리의 시작
while(mid <= end){
if(node < nodes[mid]){
break;
}
mid++;
}
// 왼쪽 서브트리 후위 순회 (start부터 mid-1까지)
postOrder(start, mid - 1);
// 오른쪽 서브트리 후위 순회 (mid부터 end까지)
postOrder(mid, end);
// 현재 노드 출력 (후위 순회에서는 루트가 마지막에 방문됨)
console.log(node);
}
let nodes = [parseInt(input[0])]
for (let i = 1; i < input.length; i++) {
nodes.push(parseInt(input[i]));
}
// 전체 트리에 대해 후위 순회 수행 (0부터 마지막 인덱스까지)
postOrder(0, nodes.length - 1);
728x90
반응형
'알고리즘 > 백준' 카테고리의 다른 글
[BAEKJOON]7785 회사에 있는 사람 (0) | 2025.05.12 |
---|---|
[BAEKJOON]13241 최소공배수 (0) | 2025.05.08 |
[BAEKJOON]11005 진법 변환 2 (0) | 2025.04.29 |
[BAEKJOON]2745 진법 변환 (0) | 2025.04.24 |
[BAEKJOON]25206 너의 평점은 (0) | 2025.04.24 |