📙 Algorithm Solving/Java
📙[Algo] 24.04.09 알고리즘
혜덕hyeduck
2024. 4. 10. 17:13
알고리즘 문제) BOJ 2250. 트리의 높이와 너비
문제 요약
- 이진트리를 격자에 다음과 같은 규칙에 따라 그림
- 같은 레벨에 있으면 같은 행
- 한 열에는 오직 한 노드만 존재
- 임의 노드의 왼쪽 서브트리 노드들은 해당 노드보다 왼쪽 열, 오른쪽 서브트리 노드들은 오른쪽 열에 위치
- 노드가 배치된 가장 왼쪽 열과 오른쪽 열 사이에 비어있는 열은 없다.
- 임의의 이진트리가 입력으로 주어질 때 너비가 가장 넓은 레벨과 그 레벨의 너비를 출력하는 프로그램을 작성
- 너비 : 각 레벨의 노드들 중 가장 오른쪽 노드 x좌표 값 - 가장 왼쪽 노드 x좌표값 + 1
- 여러개가 있다면 레벨이 작은 걸로 출력
시간 제한
- 1초
입력
- 노드 개수 나타내는 정수 N
- 1≤N≤1만
- N개의 줄에 노드 번호와 해당 노드 왼쪽 자식 노드, 오른쪽 자식 노드 번호 주어짐
- 노드 번호는 1부터 N까지
- 자식이 없으면 자식 노드 번호에 -1
출력
- 첫째 줄에 너비가 가장 넓은 레벨과 그 레벨의 너비를 순서대로 출력
- 두 개 이상 있을 때에는 번호가 작은 레벨을 출력
접근법
- 각 노드의 x좌표를 구해야할까?
- 같은 레벨에 위치한 노드들의 부모 노드끼리도 서로 같은 레벨…
- 일단 dfs로 parent배열에 각 노드별 부모 노드를 기록한다.
- 이때 원소가 0인 애가 최상위 루트 노드가 된다.
- 그리고 3번 조건에 의하면 루트 노드 기준 가장 중위 순회 진행 했을 때 가장 왼쪽 끝에 도착하는 자식의 x좌표 위치가 1이 된다.
- 그래서 해당 노드를 기준으로 중위 순회 진행하면서 x좌표를 하나씩 늘려가며 기록한다.
- 주의할점은 뿌리노드를 발견하면 해당 노드 기준 오른쪽 서브트리의 가장 왼쪽 자식 노드가 그 다음 x좌표 값을 갖게 된다
- 그래서 해당 노드를 기준으로 중위 순회 진행하면서 x좌표를 하나씩 늘려가며 기록한다.
- 중위순회 메소드를 구현한다 ⇒ 해당 노드 기준 Left Node 부터 방문(-1이 나올 때까지) ⇒ 가장 왼쪽 노드에 도달했다면 가장 가까운 부모 노드(뿌리) 방문 ⇒ 부모 노드 기준 Right Node 방문
코드
import java.io.*;
import java.util.*;
public class Main {
static int N;
static ArrayList<Integer>[] list;
static int[] parent;
static int root;
static ArrayList<Integer>[] posY;
static int[] posX;
static int x = 1;
static void inorder(int cur, int y) {
int leftNode = list[cur].get(0);
int rightNode = list[cur].get(1);
// 행 위치 기록
posY[y].add(cur);
if (leftNode != -1) inorder(leftNode, y + 1);
// 열 위치 기록
posX[cur] = x++;
if (rightNode != -1) inorder(rightNode, y + 1);
}
public static void main(String[] args) throws IOException{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
StringTokenizer st;
N = Integer.parseInt(br.readLine());
list = new ArrayList[N + 1];
for (int i = 0; i < N + 1; i++) {
list[i] = new ArrayList<>();
}
int ro, le, ri;
parent = new int[N + 1];
for (int i = 0; i < N; i++) {
st = new StringTokenizer(br.readLine());
ro = Integer.parseInt(st.nextToken());
le = Integer.parseInt(st.nextToken());
ri = Integer.parseInt(st.nextToken());
list[ro].add(le);
list[ro].add(ri);
// 부모 노드 기록하기 -> 여기서 주의(처음에 dfs로 찾는 것보다 그냥 입력받을 때 기록)
if (le != -1) parent[le] = ro;
if (ri != -1) parent[ri] = ro;
}
// 최상위 뿌리 노드 찾기
for (int i = 1; i <= N; i++) {
if (parent[i] == 0) {
root = i;
break;
}
}
// x,y좌표 기록하기
posY = new ArrayList[N + 1];
for (int i = 0; i < N + 1; i++) {
posY[i] = new ArrayList<>();
}
posX = new int[N + 1];
inorder(root, 1);
int max = 0, level = 0, lidx, ridx, dist;
for (int i = 1; i < N + 1; i++) {
if (posY[i].isEmpty()) break;
lidx = posY[i].get(0);
ridx = posY[i].get(posY[i].size() - 1);
dist = posX[ridx] - posX[lidx] + 1;
if (max < dist) {
max = dist;
level = i;
}
}
bw.write(level + " " + max);
bw.flush();
bw.close();
br.close();
}
}