[백준 4256] 트리(Java)

최민길(Gale)·2023년 11월 23일
1

알고리즘

목록 보기
154/172

문제 링크 : https://www.acmicpc.net/problem/4256

이 문제는 트리의 성질을 이용하여 풀 수 있습니다.

우선 전위 순회의 경우 루트 노드부터 시작하여 리프 노드까지 탐색합니다. 따라서 가장 먼저 루트 노드가 나오고, 그 다음 인덱스가 루트 노드의 자식 노드 순으로 내려갑니다.

반면 중위 순회의 경우 왼쪽에서 오른쪽으로 탐색합니다. 따라서 루트 노드값을 안다면 그 값을 기준으로 왼쪽은 왼쪽 자식 노드, 오른쪽은 오른쪽 자식 노드가 됩니다.

이를 동시에 적용하면 다음과 같이 트리를 구현할 수 있습니다.

  1. 전위 순회를 진행하면서 현재의 부모 노드를 체크
  2. 부모 노드를 기준으로 중위 순회 배열을 두 개로 나눔(왼쪽, 오른쪽)
  3. 각각의 나눈 배열을 재귀함수를 이용하여 탐색한 결과를 트리의 자식 노드로 설정

이를 조금 더 구체적으로 설명해보겠습니다.

우선 가장 먼저 전위 순회 배열의 0번 인덱스를 탐색합니다. 이 값은 트리 전체의 루트 노드가 됩니다. 이 루트 노드와 같은 값을 가지는 중위 순회 배열의 인덱스를 구합니다. 이 인덱스를 구하는 이유는 이 값을 기준으로 중위 순회 배열의 왼쪽은 왼쪽 자식 노드, 오른쪽은 오른쪽 자식 노드이기 때문입니다.

위에서 구한 정보를 바탕으로 트리를 구현합니다. 재귀함수는 트리의 노드를 반환하여 부모 노드의 값을 가지는 노드를 생성한 후 왼쪽 자식 노드를 위에서 구한 왼쪽 자식 노드, 오른쪽 자식 노드를 오른쪽 자식 노드값으로 치환합니다. 이 때 재귀호출을 이용하여 위의 과정을 반복합니다.

이 때 전위 순회의 어떤 인덱스부터 탐색할지를 정해야 합니다. 중위 순회에서 왼쪽의 원소들의 개수가 곧 왼쪽 자식 노드의 개수이기 때문에 전위 순회에서 첫 번째 노드를 제외하고 왼쪽의 원소들의 개수만큼 건너뛰면 오른쪽 자식 노드가 시작합니다. 이 때 전위 순회 특성상 가장 먼저 오는 인덱스가 오른쪽 자식 노드의 부모 노드이기 때문에 그 인덱스를 가리키게 리턴합니다.

다음은 코드입니다.

import java.util.*;
import java.io.*;

class Main{
    static class Node{
        int val;
        Node left, right;

        Node(int val){
            this.val = val;
        }
    }

    static int N;
    static StringBuilder sb = new StringBuilder();

    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        while(T-- >0){
            N = Integer.parseInt(br.readLine());
            int[] preorder = new int[N];
            StringTokenizer st = new StringTokenizer(br.readLine());
            for(int i=0;i<N;i++) preorder[i] = Integer.parseInt(st.nextToken());

            st = new StringTokenizer(br.readLine());
            int[] inorder = new int[N];
            for(int i=0;i<N;i++) inorder[i] = Integer.parseInt(st.nextToken());

            Node tree = buildTree(0, preorder, inorder);
            postOrder(tree);
            sb.append("\n");
        }
        System.out.println(sb);
    }

    static void postOrder(Node node){
        if(node == null) return;

        postOrder(node.left);
        postOrder(node.right);
        sb.append(node.val).append(" ");
    }

    static Node buildTree(int idx, int[] preorder, int[] inorder){
        if(idx >= N) return null;

        int root = getIndex(preorder[idx], inorder);
        if(root == -1) return null;
        int[] leftArr = Arrays.copyOfRange(inorder, 0, root);
        int[] rightArr = Arrays.copyOfRange(inorder, root+1, inorder.length);

        Node node = new Node(inorder[root]);
        node.left = buildTree(idx+1, preorder, leftArr);
        node.right = buildTree(idx+root+1, preorder, rightArr);
        return node;
    }

    static int getIndex(int target, int[] inorder){
        for(int i=0;i<inorder.length;i++){
            if(inorder[i] == target) return i;
        }
        return -1;
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글

관련 채용 정보