자바 코딩테스트 강좌, 플로이드-워셜

안녕하세요! 이번 강좌에서는 자바 코딩테스트에서 자주 출제되는 플로이드-워셜 알고리즘에 대해 배워보도록 하겠습니다. 플로이드-워셜 알고리즘은 모든 지점에서 다른 모든 지점까지의 최단 경로를 찾는 데 효율적인 방법입니다. 특히, 그래프의 정점 수가 적은 경우 유용하게 사용됩니다. 이번 글에서는 플로이드-워셜 알고리즘을 적용한 문제를 풀어보며, 그 과정을 자세히 설명하겠습니다.

문제 설명

다음은 플로이드-워셜 알고리즘을 활용한 문제입니다.

문제: 주어진 N개의 도시와 도시 간의 도로 정보를 이용하여, 모든 도시 간의 최단 경로를 구하시오. 
각 도시는 1부터 N까지 번호가 붙어 있으며, 도로는 양방향으로 연결되어 있습니다. 
도로 정보는 다음과 같은 형식으로 주어집니다: 

N  M
x y z 

여기서 N은 도시의 수, M은 도로의 수, x는 도로의 한 쪽 도시, y는 도로의 다른 쪽 도시, z는 두 도시 간의 거리입니다. 
자신과의 거리(예: 1번 도시에서 1번 도시까지의 거리)는 항상 0으로 설정되어 있습니다. 
두 도시 간의 직접적인 도로가 여러 개 있을 경우, 거리 값이 가장 작은 도로 정보만을 고려합니다.

입력 예시:
4 7
1 2 4
1 3 2
2 3 5
2 4 10
3 4 3
1 4 8
3 1 3

출력 예시:
0 2 3 5
2 0 5 3
3 5 0 3
5 3 3 0

문제 풀이 과정

이제 이 문제를 해결하기 위해 플로이드-워셜 알고리즘을 구현해 보겠습니다. 다음은 알고리즘을 단계별로 설명한 것입니다.

1. 데이터 구조 설정

먼저, 모든 도시 간의 거리 정보를 저장할 2차원 배열을 설정합니다. N개의 도시가 있으므로 배열의 크기는 dist[N + 1][N + 1]으로 합니다. 배열의 모든 요소는 초기값으로 무한대(Integer.MAX_VALUE)로 설정합니다. 그러나 각 도시에서 자신까지의 거리는 0으로 설정합니다.

int[][] dist = new int[N + 1][N + 1];

for (int i = 1; i <= N; i++) {
    Arrays.fill(dist[i], Integer.MAX_VALUE);
    dist[i][i] = 0;
}

2. 도로 정보를 입력받아 거리 배열 초기화

입력받은 도로 정보를 통해 각 도시 간의 거리 정보를 설정합니다. 만약 두 도시 간에 여러 개의 도로가 주어진 경우, 거리 배열에는 가장 짧은 거리만 저장합니다.

for (int i = 0; i < M; i++) {
    int x = sc.nextInt();
    int y = sc.nextInt();
    int z = sc.nextInt();
    dist[x][y] = Math.min(dist[x][y], z);
    dist[y][x] = Math.min(dist[y][x], z);
}

3. 플로이드-워셜 알고리즘 구현

플로이드-워셜 알고리즘의 핵심은 삼중 루프를 통해 모든 짝의 최단 거리를 반복적으로 업데이트하는 것입니다. 아래는 플로이드-워셜 알고리즘의 구현 코드입니다.

for (int k = 1; k <= N; k++) {
    for (int i = 1; i <= N; i++) {
        for (int j = 1; j <= N; j++) {
            if (dist[i][j] > dist[i][k] + dist[k][j]) {
                dist[i][j] = dist[i][k] + dist[k][j];
            }
        }
    }
}

4. 결과 출력

마지막으로 모든 도시 간의 최단 경로를 출력합니다. 1번 도시부터 N번 도시까지의 거리를 차례대로 출력합니다.

for (int i = 1; i <= N; i++) {
    for (int j = 1; j <= N; j++) {
        if (dist[i][j] == Integer.MAX_VALUE) {
            System.out.print("INF ");
        } else {
            System.out.print(dist[i][j] + " ");
        }
    }
    System.out.println();
}

전체 코드

이제 위의 모든 과정을 하나의 자바 프로그램으로 통합해 보겠습니다. 아래는 문제를 해결하기 위한 전체 자바 코드입니다.

import java.util.Arrays;
import java.util.Scanner;

public class FloydWarshall {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int N = sc.nextInt(); // 도시의 수
        int M = sc.nextInt(); // 도로의 수

        int[][] dist = new int[N + 1][N + 1];

        // 초기화
        for (int i = 1; i <= N; i++) {
            Arrays.fill(dist[i], Integer.MAX_VALUE);
            dist[i][i] = 0; // 자기 자신과의 거리는 0
        }

        // 도로 정보 입력
        for (int i = 0; i < M; i++) {
            int x = sc.nextInt();
            int y = sc.nextInt();
            int z = sc.nextInt();
            dist[x][y] = Math.min(dist[x][y], z);
            dist[y][x] = Math.min(dist[y][x], z);
        }

        // 플로이드-워셜 알고리즘
        for (int k = 1; k <= N; k++) {
            for (int i = 1; i <= N; i++) {
                for (int j = 1; j <= N; j++) {
                    if (dist[i][j] > dist[i][k] + dist[k][j]) {
                        dist[i][j] = dist[i][k] + dist[k][j];
                    }
                }
            }
        }

        // 결과 출력
        for (int i = 1; i <= N; i++) {
            for (int j = 1; j <= N; j++) {
                if (dist[i][j] == Integer.MAX_VALUE) {
                    System.out.print("INF ");
                } else {
                    System.out.print(dist[i][j] + " ");
                }
            }
            System.out.println();
        }
    }
}

정리

이번 강좌에서는 플로이드-워셜 알고리즘을 이용하여 도시 간의 최단 경로를 구하는 문제를 해결해 보았습니다. 이 알고리즘은 모든 쌍의 최단 경로를 구하는 데 유용하게 사용할 수 있으며, 코드의 구조와 로직을 이해하는 데 큰 도움이 되었을 것입니다. 실제 코딩테스트에서는 이러한 알고리즘을 활용하여 효율적인 문제 해결 능력을 키우는 것이 중요합니다.

참고: 플로이드-워셜 알고리즘의 시간 복잡도는 O(N^3)이므로, 그래프의 정점 수가 많을 경우 다른 최단 경로 알고리즘(예: 다익스트라 알고리즘)을 고려하는 것이 좋습니다.

앞으로도 알릴루야 코딩테스트 강좌에서 다양한 알고리즘을 소개하겠습니다. 감사합니다!

자바 코딩테스트 강좌, 트리의 지름 구하기

1. 문제 정의

주어진 트리에서 지름을 구하는 문제는 알고리즘적인 사고를 요구하는 중요한 주제입니다.
트리의 지름은 두 개의 정점 간의 최장 경로의 길이를 말합니다. 이는 트리 구조의 특성을 활용하여 구할 수 있으며, 여러 가지 응용 문제의 기초가 됩니다.
그러므로 이 문제를 해결하는 것은 코딩 테스트에서 괜찮은 성적을 얻기 위한 중요한 단계입니다.

2. 문제 이해하기

트리는 노드로 구성된 비선형 자료구조로서, 레벨과 부모-자식 관계가 존재합니다. 트리의 지름을 구하기 위해서는 트리를 그래프의 일종으로 생각하고
그래프 탐색 알고리즘을 사용해야 합니다.
지름을 구하는 가장 효율적인 방법은 두 번의 깊이 우선 탐색(DFS)을 사용하는 것입니다.

첫 번째 DFS는 임의의 노드에서 시작하여 가장 먼 노드를 찾습니다. 그 다음, 이 새로 찾은 노드에서 다시 DFS를 실행하여 최대 거리를 측정하면
그것이 트리의 지름이 됩니다. 이러한 방식은 O(N)의 시간 복잡도를 가지며, 이는 매우 효율적인 해결책입니다.

3. 문제 해결 전략

문제를 해결하기 위한 전략은 다음과 같습니다.

  1. 트리 구성: 먼저 주어진 데이터를 바탕으로 트리 구조를 만듭니다.
  2. DFS 구현: 깊이 우선 탐색 알고리즘을 구현하여 특정 노드에서 가장 먼 노드를 찾습니다.
  3. 지름 계산: 첫 번째 DFS에서 찾은 먼 노드에서 다시 DFS를 실행하여 지름을 계산합니다.

4. 자바 코드 구현


import java.util.*;

class TreeNode {
    int val;
    List children;

    TreeNode(int x) {
        val = x;
        children = new ArrayList<>();
    }
}

public class DiameterOfTree {

    private int maxDiameter = 0;

    public int getTreeDiameter(TreeNode root) {
        if (root == null) return 0;
        dfs(root);
        return maxDiameter;
    }

    private int dfs(TreeNode node) {
        if (node == null) return 0;

        int firstMax = 0; 
        int secondMax = 0;

        for (TreeNode child : node.children) {
            int childDepth = dfs(child);
            if (childDepth > firstMax) {
                secondMax = firstMax;
                firstMax = childDepth;
            } else if (childDepth > secondMax) {
                secondMax = childDepth;
            }
        }

        maxDiameter = Math.max(maxDiameter, firstMax + secondMax);
        return firstMax + 1;
    }

    public static void main(String[] args) {
        TreeNode root = new TreeNode(1);
        TreeNode node2 = new TreeNode(2);
        TreeNode node3 = new TreeNode(3);
        TreeNode node4 = new TreeNode(4);
        TreeNode node5 = new TreeNode(5);

        root.children.add(node2);
        root.children.add(node3);
        node2.children.add(node4);
        node2.children.add(node5);

        DiameterOfTree diameter = new DiameterOfTree();
        int result = diameter.getTreeDiameter(root);
        System.out.println("트리의 지름: " + result);
    }
}

            

위의 코드는 우선 TreeNode 클래스를 정의하고, 각 노드를 연결하는 트리를 만듭니다.
main 메소드는 트리를 설정하고 getTreeDiameter 메소드를 통하여 지름을 계산하도록 되어 있습니다.

5. 코드 설명

이 부분에서는 코드의 주요 부분을 설명하겠습니다.

TreeNode 클래스

TreeNode 클래스는 트리의 각 노드를 나타내며, 노드의 값과 자식 노드 리스트를 포함합니다.
생성자에서 값과 빈 자식 리스트를 초기화합니다.

diameter 변수를 이용한 DFS

DFS는 각 노드를 탐색하면서 자식 노드들의 깊이를 구하고, 최대 깊이를 구합니다.
동시에 최대 지름을 계산할 때, 두 개의 최대 깊이를 사용하여 업데이트합니다.
이 깊이 값은 부모 노드로 돌아갈 때 1을 더해 반환됩니다.

6. 성능 분석

위의 구현은 O(N)의 시간 복잡도를 가지며, 여기서 N은 노드의 수입니다.
각 노드를 한 번씩 방문하므로 매우 효율적입니다.
공간 복잡도 또한 O(H)로, 여기서 H는 트리의 높이에 해당합니다.
이러한 성능은 실제 대규모 데이터에 대해서도 매우 좋은 성능을 보일 것입니다.

7. 다양한 테스트 케이스

다양한 트리 구조를 갖는 테스트 케이스를 통해 알고리즘을 검증할 수 있습니다.
예를 들어, 다음과 같은 트리 구조를 고려할 수 있습니다:

  • 단일 노드 트리
  • 모든 노드가 직렬로 연결된 스패닝 트리
  • 균형 트리
  • 불균형 트리

각 구조에 대해 지름이 올바르게 계산되는지 검증함으로써 알고리즘의 신뢰도를 높일 수 있습니다.

8. 결론

트리의 지름을 구하는 문제는 알고리즘의 기초 개념을 이해하고, DFS를 활용한 효율적인 문제 해결 능력을 강화하는 데 매우 중요한 문제입니다.
제시된 방법을 통해 많은 코딩 테스트 문제를 해결할 수 있는 기반을 마련할 수 있습니다.
자바 언어를 활용한 이 방법론이 여러 상황에 적용될 수 있음을 기억하며, 다양한 문제를 해결하는 데 도움이 되길 바랍니다.

자바 코딩테스트 강좌, 특정 거리의 도시 찾기

안녕하세요, 여러분! 오늘은 자바를 활용한 취업 준비를 위한 알고리즘 문제를 다루어 보겠습니다. 이번 주제는 “특정 거리의 도시 찾기”로, 그래프 이론과 BFS(너비 우선 탐색) 알고리즘을 활용할 것입니다. 이 문제를 풀면서 알고리즘의 바탕이 되는 개념들과 자바의 유용한 자료구조를 어떻게 활용할 수 있는지 심도 깊게 알아보겠습니다.

문제 설명

주어진 도시들이 서로 길로 연결되어 있고, 각 도시는 번호로 표시됩니다. 만약 1번 도시에서 출발하여 특정 거리 K를 이동했을 때 도달할 수 있는 도시를 모두 찾아 반환하는 문제입니다. 즉, 입력으로는 도시의 수 N, 도로의 수 M, 출발 도시 X, 그리고 목표 거리 K가 주어지며, 도달할 수 있는 도시 번호를 오름차순으로 정렬하여 출력해야 합니다.

입력

  • 첫 번째 줄: 도시의 수 N (1 ≤ N ≤ 30000), 도로의 수 M (1 ≤ M ≤ 200000)
  • 두 번째 줄: 출발 도시 번호 X (1 ≤ X ≤ N)와 목표 거리 K (0 ≤ K ≤ 30000)
  • 다음 M줄: 연결된 두 도시 A, B (1 ≤ A, B ≤ N, A ≠ B)

출력

목표 거리 K에 도달할 수 있는 도시의 번호를 오름차순으로 출력합니다. 만약 도달할 수 있는 도시는 없다면 -1을 출력합니다.

풀이 접근법

이 문제를 해결하기 위해 우리는 그래프를 구성하고 BFS 알고리즘을 사용하여 주어진 거리 K에 도달 가능한 도시를 찾아야 합니다. BFS는 그래프의 모든 정점을 레벨 순서대로 방문하기 때문에 특정 거리의 도시에 도달하는 데 적합한 방법입니다.

1단계: 그래프 표현

도시 간의 도로 관계를 표현하기 위해 인접 리스트를 사용합니다. 자바에서는 ArrayList를 활용하여 각 도시의 인접 도시를 저장할 수 있습니다. 이렇게 하면 메모리 사용을 최소화하고 도시 간의 관계를 쉽게 관리할 수 있습니다.

2단계: BFS 구현

BFS를 구현하기 위해 큐를 사용합니다. 큐는 현재 도시와 현재 거리를 저장하며, 이 거리가 K에 도달할 때까지 탐색을 계속합니다. 탐색 과정에서 이미 방문한 도시는 다시 방문하지 않도록 주의해야 합니다. 또한 목표 거리를 정확히 K와 비교해야 합니다.

3단계: 결과 출력

목표 거리 K에 도달한 도시를 수집하여 오름차순으로 정렬한 후 출력합니다. 만약 아무 도시도 도달하지 못했다면 -1을 출력합니다.

자바 코드 예시


import java.util.*;

public class SpecificDistanceCity {
    static ArrayList[] graph;
    static boolean[] visited;
    static int[] distance;

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        int N = sc.nextInt(); // 도시의 수
        int M = sc.nextInt(); // 도로의 수
        int X = sc.nextInt(); // 출발 도시
        int K = sc.nextInt(); // 목표 거리

        // 그래프 초기화
        graph = new ArrayList[N + 1];
        for (int i = 1; i <= N; i++) {
            graph[i] = new ArrayList<>();
        }

        // 도로 정보 입력받기
        for (int i = 0; i < M; i++) {
            int A = sc.nextInt();
            int B = sc.nextInt();
            graph[A].add(B);
        }

        // 결과 출력
        List result = bfs(X, K);
        if (result.isEmpty()) {
            System.out.println(-1);
        } else {
            Collections.sort(result);
            for (int city : result) {
                System.out.println(city);
            }
        }

        sc.close();
    }

    private static List bfs(int start, int targetDistance) {
        List reachableCities = new ArrayList<>();
        Queue queue = new LinkedList<>(); // 도시와 현재 거리
        visited = new boolean[graph.length];
        distance = new int[graph.length];

        queue.offer(new int[]{start, 0}); // (도시, 거리)
        visited[start] = true;

        while (!queue.isEmpty()) {
            int[] current = queue.poll();
            int currentCity = current[0];
            int currentDistance = current[1];

            // 목표 거리일 때 도시 추가
            if (currentDistance == targetDistance) {
                reachableCities.add(currentCity);
            }

            // 다음 거리로 이동
            for (int neighbor : graph[currentCity]) {
                if (!visited[neighbor] && currentDistance + 1 <= targetDistance) {
                    visited[neighbor] = true;
                    queue.offer(new int[]{neighbor, currentDistance + 1});
                }
            }
        }

        return reachableCities;
    }
}

코드 설명

위 코드는 크게 세 부분으로 나눌 수 있습니다. 메인 함수에서 그래프를 초기화하고 도로 정보를 입력받은 후, BFS를 통해 도달 가능한 도시를 탐색합니다. BFS 함수는 큐를 이용하여 현재 도시와 거리를 관리하며, 목적지에 도달했을 때 그 도시를 결과 리스트에 추가합니다. 모든 BFS 탐색이 끝난 후에는 도달 가능한 도시를 정렬하여 출력합니다.

직접 해보기

이제 여러분이 직접 코드를 실행해 보세요. 다양한 입력 데이터로 테스트하여 원하는 출력이 나오는지 확인해보세요. 더불어 코드의 각 부분에 대해 주석을 추가하거나, 조건문을 변경해 보면서 코드의 동작을 실험해 보는 것도 좋습니다. 이를 통해 알고리즘에 대한 이해가 더욱 깊어질 것입니다.

마무리

이번 강좌를 통해 특정 거리의 도시를 찾는 문제를 해결하기 위한 기초적인 BFS 알고리즘과 그래프의 구현 방법을 배웠습니다. 취업이 목표인 만큼 이러한 문제들을 많이 풀어보며 실력을 쌓아가시길 바랍니다. 다음 강좌에서는 더 어려운 주제를 다루기로 하겠습니다. 감사합니다!

작성자: 자바 코딩테스트 강좌

연락처: example@example.com

자바 코딩테스트 강좌, 트리의 부모 찾기

코딩 테스트는 많은 기업에서 필수적으로 요구하는 과정이며, 특히 데이터 구조와 알고리즘에 대한 이해는 핵심 역량으로 자리 잡고 있습니다. 이 글에서는 트리 구조와 그 부모 노드를 찾는 문제를 다룰 것입니다. 이 문제의 중요성과 해결 방법, 그리고 자바로 해결하는 과정을 상세히 설명하도록 하겠습니다.

문제 설명

트리 구조는 노드의 계층적 관계를 나타내는 자료구조입니다. 각 노드는 자식 노드를 가질 수 있으며, 이와 같이 간단한 구조 속에서도 다양한 문제가 발생할 수 있습니다. 이번 문제에서는 주어진 노드의 부모 노드를 찾는 것입니다.

문제 정의

주어진 트리와 특정 노드의 값을 입력받아 해당 노드의 부모 노드를 반환하는 프로그램을 작성하시오. 만약 입력된 노드가 루트 노드이거나 존재하지 않는 경우에는 -1을 반환해야 합니다.

입력 형식

첫 번째 줄: 노드의 개수  (1 ≤ N ≤ 100,000)
두 번째 줄: 각 노드의 부모 노드 정보 (공백으로 구분된 정수로 나타냄)
세 번째 줄: 찾고자 하는 노드 

출력 형식

부모 노드의 값 또는 -1

문제 해결 접근 방식

우리는 주어진 트리의 부모 노드를 빠르게 찾기 위해 몇 가지 방법을 사용할 수 있습니다. 주로 사용하는 방법은 배열을 통한 접근입니다. 부모 노드 정보를 배열로 저장하면, 특정 노드의 부모를 상수 시간에 찾을 수 있습니다. 이 과정은 다음과 같습니다:

1. 데이터 구조 선택

노드의 부모 정보를 효과적으로 저장하기 위해, 우리는 배열을 사용할 것입니다. 배열의 인덱스가 노드의 값에 해당하고, 각 인덱스에 저장된 값이 부모 노드의 값입니다. 예를 들어, 노드의 부모 정보가 다음과 같다면:

[-1, 0, 0, 1, 1, 2]

위 배열에서:

  • 노드 0의 부모: -1 (루트 노드)
  • 노드 1의 부모: 0
  • 노드 2의 부모: 0
  • 노드 3의 부모: 1
  • 노드 4의 부모: 1
  • 노드 5의 부모: 2

2. 알고리즘 설계

이제 알고리즘을 설계합니다. 전체 과정은 다음과 같습니다:

  1. 부모 정보를 저장할 배열을 초기화합니다.
  2. 부모 정보 배열을 입력받습니다.
  3. 찾고자 하는 노드를 입력받습니다.
  4. 입력된 노드가 배열의 범위 내에 있는지 확인합니다.
  5. 부모 노드를 찾고 반환합니다.
  6. 부모 노드가 루트 노드일 경우 -1을 반환합니다.

자바 코드 구현

이제 위에서 설명한 알고리즘을 자바로 구현해 보도록 하겠습니다. 우선 필요한 클래스를 정의하고, 메인 메서드를 작성하겠습니다:

import java.util.Scanner;

public class FindParentNode {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        
        // 노드의 개수 입력
        int n = sc.nextInt();
        int[] parents = new int[n];
        
        // 부모 정보 입력
        for (int i = 0; i < n; i++) {
            parents[i] = sc.nextInt();
        }
        
        // 찾고자 하는 노드 입력
        int target = sc.nextInt();
        
        // 부모 노드 찾기
        int result = findParent(parents, target);
        System.out.println(result);
        
        sc.close();
    }
    
    // 부모 노드 찾기 메서드
    public static int findParent(int[] parents, int node) {
        if (node < 0 || node >= parents.length) {
            return -1; // 존재하지 않는 노드
        }
        // 부모 노드 반환
        return parents[node];
    }
}

설명

위 코드에서, 우리는 Scanner 클래스를 사용하여 입력을 받고, parents 배열에 부모 정보를 저장합니다. 나중에 목표 노드를 입력받고, findParent 메서드를 호출하여 부모 노드를 찾습니다. 이 메서드는 입력된 노드가 유효한지 확인 후, 해당 노드의 부모를 반환합니다.

테스트 케이스

이제 구현된 코드가 올바르게 작동하는지 확인하기 위해 몇 가지 테스트 케이스를 만들어 보겠습니다.

테스트 케이스 1

입력:

6
-1 0 0 1 1 2
3

출력:

1

테스트 케이스 2

입력:

6
-1 0 0 1 1 2
0

출력:

-1

테스트 케이스 3

입력:

6
-1 0 0 1 1 2
6

출력:

-1

결론

이번 포스팅을 통해 자바로 트리의 부모 노드를 찾는 문제를 해결하는 과정을 살펴보았습니다. 트리 구조는 데이터 구조의 기본 개념 중 하나이며, 기본적인 부모-자식 관계를 이해했으므로 다른 복잡한 트리 문제를 해결하는데도 유용할 것입니다. 코딩 테스트에 대비하기 위해 여러 가지 문제를 풀어보고 자신만의 풀이 과정을 만들어 나가기를 바랍니다.

자바 코딩테스트 강좌, 트리 알아보기

트리는 프로그래밍에서 자주 사용되는 자료구조로, 노드와 간선으로 이루어진 연결 구조입니다. 각 노드는 데이터와 연결 정보를 가지며, 하나의 루트 노드를 가지며 자식 노드로 연결됩니다. 이 글에서는 트리의 기본 개념과 트리와 관련된 문제를 해결하는 방법을 알아보겠습니다.

트리의 기본 개념

트리는 다음과 같은 용어로 이루어져 있습니다:

  • 노드(Node): 데이터와 그 데이터를 연결하는 정보를 포함하는 구조입니다.
  • 루트 노드(Root Node): 트리의 최상위 노드입니다.
  • 부모 노드(Parent Node): 자식 노드를 갖는 노드입니다.
  • 자식 노드(Child Node): 부모 노드에 연결된 노드입니다.
  • 리프 노드(Leaf Node): 자식 노드가 없는 노드입니다.
  • 깊이(Depth): 루트 노드에서 특정 노드까지의 경로 길이입니다.
  • 높이(Height): 특정 노드에서 가장 깊은 리프 노드까지의 경로 길이입니다.

문제 정의

자바를 사용하여 다음과 같은 트리 관련 문제를 해결해봅시다. 주어진 이진 트리의 깊이를 구하는 문제입니다.

문제: 이진 트리의 깊이 구하기

public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}

public class Solution {
    public int maxDepth(TreeNode root) {
        if (root == null) {
            return 0;
        } else {
            int leftDepth = maxDepth(root.left);
            int rightDepth = maxDepth(root.right);
            return Math.max(leftDepth, rightDepth) + 1;
        }
    }
}

문제 해결 과정

1. 문제 이해하기

이 문제는 주어진 이진 트리를 순회하여 각각의 노드의 깊이를 계산하는 것입니다. 이때 깊이는 루트 노드에서 시작하여 특정 노드까지의 간선 수로 정의됩니다.

2. 해결 방법 선택하기

이 문제를 해결하기 위해 재귀적 방식으로 트리를 탐색하는 방법을 사용할 것입니다. 현재 노드가 null인 경우에는 깊이가 0임을 의미하며, 그렇지 않을 경우 왼쪽 서브트리와 오른쪽 서브트리의 깊이를 재귀 호출을 통해 구하고, 둘 중 큰 값을 선택하여 1을 더하는 방식으로 계산합니다.

3. 코드 작성하기

위 접근 방식을 통해 코드를 작성합니다.

public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;

    TreeNode(int x) {
        val = x;
    }
}

public class Solution {
    public int maxDepth(TreeNode root) {
        // 기저 사례: 빈 노드일 때
        if (root == null) {
            return 0;
        }

        // 왼쪽과 오른쪽 서브트리의 깊이 재귀적으로 구하기
        int leftDepth = maxDepth(root.left);
        int rightDepth = maxDepth(root.right);

        // 둘 중 큰 값에 1 더한 값을 반환
        return Math.max(leftDepth, rightDepth) + 1;
    }
}

4. 시간 복잡도 분석

이 알고리즘의 시간 복잡도는 O(n)입니다. 여기서 n은 트리 내의 노드 수를 의미합니다. 이는 모든 노드를 한 번씩 방문해야 하기 때문입니다.

5. 최종 코드 및 테스트

이제 완성된 코드를 테스트하여 올바르게 동작하는지 확인해봅시다.

public class Main {
    public static void main(String[] args) {
        TreeNode root = new TreeNode(1);
        root.left = new TreeNode(2);
        root.right = new TreeNode(3);
        root.left.left = new TreeNode(4);
        root.left.right = new TreeNode(5);

        Solution solution = new Solution();
        System.out.println("트리의 깊이는: " + solution.maxDepth(root)); // 출력: 3
    }
}

6. 결론

이번 강좌에서는 트리의 기본 개념과 이진 트리의 깊이를 구하는 알고리즘 문제를 다루어봤습니다. 재귀적 접근 방식이 이 문제를 효과적으로 해결할 수 있음을 알 수 있었습니다. 다양한 트리 문제를 해결하는 데 있어 이러한 기초 개념이 매우 중요하며, 더 복잡한 문제를 풀이하는 데 도움이 될 것입니다.

참고사항: 트리에 대한 이해도를 높이기 위해 다양한 형태의 트리 문제를 연습하시기 바랍니다. 특히, 이진 검색 트리, 균형 이진 트리 그리고 트리 순회 방법 등을 공부하면 좋습니다.

추가 자료