자바 코딩테스트 강좌, 깊이 우선 탐색

코딩테스트의 많은 문제들은 그래프 또는 트리 구조를 기반으로 하고 있습니다. 이러한 문제를 해결하는 데 유용한 알고리즘 중 하나가 깊이 우선 탐색(Depth-First Search, DFS)입니다. 이번 강좌에서는 DFS의 개념과 자바로 구현하는 방법을 알아보겠습니다.

1. 깊이 우선 탐색(DFS)란?

깊이 우선 탐색은 그래프 탐색 알고리즘의 일종으로, 가능한 한 깊이 들어가면서 노드를 탐색하는 방법입니다. 즉, 한 갈래로 계속 나아가다가 더 이상 진행할 수 없게 되면 한 단계 앞의 노드로 되돌아가서 다른 갈래를 탐색하는 방식입니다.

2. DFS의 특징

  • 스택을 사용하여 방문한 노드를 저장합니다.
  • 재귀(recursion)를 통해 구현될 수 있습니다.
  • 너비 우선 탐색(BFS)과는 달리 노드의 깊이나 경로를 우선 고려합니다.

3. 문제 정의

다음과 같은 그래프가 있다고 가정해 봅시다:

        A
       / \
      B   C
     / \   \
    D   E   F
    

이 그래프에서 DFS를 사용하여 A에서 시작해 D까지의 경로를 찾아보려 합니다. 경로를 찾고 A에서 D까지 방문한 노드를 출력하는 것이 목표입니다.

4. 문제 해결 과정

DFS를 사용하여 문제를 해결하기 위해, 먼저 그래프를 표현한 후 DFS 알고리즘을 구현해야 합니다.

4.1 그래프 표현

그래프는 보통 인접 리스트나 인접 행렬로 표현할 수 있습니다. 여기서는 인접 리스트를 사용하여 그래프를 표현하겠습니다.

자바로 그래프 구현하기

    import java.util.*;

    class Graph {
        private Map> adjacencyList;

        public Graph() {
            adjacencyList = new HashMap<>();
        }

        public void addEdge(String source, String destination) {
            adjacencyList.putIfAbsent(source, new ArrayList<>());
            adjacencyList.get(source).add(destination);
        }
        
        public Map> getAdjacencyList() {
            return adjacencyList;
        }
    }
    

4.2 DFS 알고리즘 구현

DFS 알고리즘은 다음과 같은 방식으로 구현될 수 있습니다. 방문한 노드를 저장하기 위해 Set을 사용하고 재귀 호출을 통해 깊이 탐색을 수행합니다.

자바 DFS 메서드

    class DFS {
        private Set visited;
        private List path;

        public DFS() {
            visited = new HashSet<>();
            path = new ArrayList<>();
        }

        public void depthFirstSearch(Graph graph, String node) {
            if (!visited.contains(node)) {
                visited.add(node);
                path.add(node);
                
                for (String neighbor : graph.getAdjacencyList().get(node)) {
                    depthFirstSearch(graph, neighbor);
                }
            }
        }

        public List getPath() {
            return path;
        }
    }
    

5. 전체 코드

이제 전체 코드를 하나로 합쳐서 사용해 보겠습니다. 다음은 그래프를 만들고 DFS를 실행하는 전체 코드입니다.

    public class Main {
        public static void main(String[] args) {
            Graph graph = new Graph();
            graph.addEdge("A", "B");
            graph.addEdge("A", "C");
            graph.addEdge("B", "D");
            graph.addEdge("B", "E");
            graph.addEdge("C", "F");

            DFS dfs = new DFS();
            dfs.depthFirstSearch(graph, "A");

            System.out.println("DFS 경로: " + dfs.getPath());
        }
    }
    

6. 코드 실행 결과

위 코드를 실행하면 다음과 같은 결과를 얻을 수 있습니다:

    DFS 경로: [A, B, D, E, C, F]
    

결과에서 보듯이 DFS는 A에서 시작하여 B를 방문하고 그 후 D로 깊이 들어갔습니다. DFS의 탐색 순서가 유지되는 것을 확인할 수 있습니다.

7. 심화 학습

이 강좌에서는 DFS의 개념과 기본적인 구현 방법을 소개했습니다. 더 나아가 DFS를 활용한 다양한 문제들을 풀어보며 실력을 쌓아가는 것이 좋습니다. 대표적인 문제로는:

  • 미로 탐색
  • 연결 요소 찾기
  • 사이클 검출

8. 결론

이번 강좌를 통해 깊이 우선 탐색의 기본 개념과 자바에서의 구현 방법을 배웠습니다. 그래프 문제는 코딩테스트에서 자주 출제되므로 반드시 숙지하고 연습해보시기 바랍니다. 다음 강좌에서는 다른 탐색 알고리즘인 너비 우선 탐색(BFS)에 대해 다뤄보겠습니다.

자바 코딩테스트 강좌, 기수 정렬

안녕하세요! 오늘은 기수 정렬(Radix Sort)에 대해 알아보겠습니다. 기수 정렬은 정수나 문자열의 각 자리수를 기준으로 정렬하는 알고리즘으로, 특정 조건 하에 매우 효율적으로 작동합니다. 이 글에서는 기수 정렬의 개념, 동작 방식, 그리고 자바로 구현하는 방법에 대해 설명하겠습니다. 기수 정렬을 통해 알고리즘 문제풀이 능력을 한 단계 끌어올리길 바랍니다.

1. 기수 정렬의 개념

기수 정렬은 대표적인 비교 기반 정렬이 아니라, 비교하지 않고 키의 자리수를 이용하여 정렬하는 비교 비정렬 방식입니다. 일반적으로 기수 정렬은 다음과 같은 주요 단계를 거칩니다:

  • 모든 숫자를 자리수 단위로 분리
  • LSB(Least Significant Bit)부터 가장 우측 자리수부터 정렬 시작
  • 엄격한 정렬이 이루어지도록 자리를 메우기
  • 모든 자리수에 대해 반복하여 최종 정렬 완료

기수 정렬의 시간 복잡도는 O(n*k)입니다. 여기서 n은 데이터의 개수, k는 숫자의 자리수입니다. 따라서, 기수 정렬은 자리수가 적은 경우, 또는 데이터의 개수가 많지 않은 경우에 효율적입니다.

2. 기수 정렬의 동작 방식

기수 정렬의 작동 원리를 이해하기 위해 간단한 예제를 통해 설명하겠습니다. 다음 배열을 기수 정렬을 이용해 정렬한다고 가정해 보겠습니다:

[170, 45, 75, 90, 802, 24, 2, 66]

이 배열에서 기수 정렬은 다음과 같은 단계로 진행됩니다:

Step 1: LSB(Least Significant Bit) 기준으로 정렬

최하위 자리수(1의 자리)를 기준으로 배열을 정렬합니다:

[170, 90, 802, 24, 2, 45, 75, 66]

1의 자리에서 작은 숫자를 먼저 배치하게 됩니다.

Step 2: 10의 자리 기준으로 정렬

이번에는 10의 자리를 기준으로 정렬합니다:

[170, 802, 24, 2, 45, 75, 90, 66]

이렇게 한 자리씩 순차적으로 진행해 나갑니다.

Step 3: 100의 자리 기준으로 정렬

마지막으로 100의 자리를 기준으로 정렬하면:

[2, 24, 45, 66, 75, 90, 170, 802]

이제 배열이 완전히 정렬된 것을 볼 수 있습니다.

3. 기수 정렬 자바 코드 구현

이제 자바로 기수 정렬을 구현해 보겠습니다. 아래의 코드를 사용하여 기수 정렬을 수행할 수 있습니다:


    public class RadixSort {
        // 주어진 배열의 최댓값을 찾아 반환하는 메서드
        static int getMax(int[] arr, int n) {
            int max = arr[0];
            for (int i = 1; i < n; i++) {
                if (arr[i] > max) {
                    max = arr[i];
                }
            }
            return max;
        }

        // 특정 자리수에 대해 counting sort를 수행하는 메서드
        static void countingSort(int[] arr, int n, int exp) {
            int[] output = new int[n]; // 정렬된 결과를 담을 배열
            int[] count = new int[10]; // 0~9까지의 숫자에 대해 카운트

            for (int i = 0; i < n; i++) {
                count[(arr[i] / exp) % 10]++;
            }

            for (int i = 1; i < 10; i++) {
                count[i] += count[i - 1];
            }

            for (int i = n - 1; i >= 0; i--) {
                output[count[(arr[i] / exp) % 10] - 1] = arr[i];
                count[(arr[i] / exp) % 10]--;
            }

            for (int i = 0; i < n; i++) {
                arr[i] = output[i];
            }
        }

        // 기수 정렬 메서드
        static void radixSort(int[] arr) {
            int n = arr.length;
            int max = getMax(arr, n);

            for (int exp = 1; max / exp > 0; exp *= 10) {
                countingSort(arr, n, exp);
            }
        }

        // 메인 메서드
        public static void main(String[] args) {
            int[] arr = {170, 45, 75, 90, 802, 24, 2, 66};
            radixSort(arr);

            System.out.println("정렬된 배열: ");
            for (int num : arr) {
                System.out.print(num + " ");
            }
        }
    }
    

이 코드는 숫자의 각 자리별로 정렬을 수행하여 최종적으로 오름차순으로 정렬된 배열을 출력합니다. getMax, countingSort, radixSort 메서드를 통해 각 단계의 역할을 구현하고 있어, 기수 정렬의 작동 원리를 쉽게 이해할 수 있습니다.

4. 기수 정렬의 장단점

장점

  • O(n * k)의 시간 복잡도로, 규칙적인 데이터의 정렬에 매우 효율적입니다.
  • 접근 패턴이 예측 가능하므로 데이터베이스와 같은 시스템에서 유리합니다.

단점

  • 메모리 사용이 추가로 필요하여 큰 데이터셋에는 적합하지 않을 수 있습니다.
  • 부동소수점 숫자에는 적용하기 어렵습니다.

5. 기수 정렬 응용 문제

이제 기수 정렬을 활용해볼 수 있는 간단한 문제를 풀어보겠습니다.

문제 설명

정수 배열이 주어질 때, 기수 정렬을 사용하여 배열을 오름차순으로 정렬하라. 단, 배열의 최대 길이는 1000이며, 각 원소는 0 이상 10000 이하의 정수이다.

제한 사항

  • 기수 정렬을 반드시 사용해야 하며, 다른 정렬 알고리즘을 사용해서는 안 된다.
  • 불필요한 변수를 사용하지 않고도 해결해야 한다.

해결 과정

위의 문제를 해결하기 위해 기수 정렬 알고리즘을 그대로 적용하면 됩니다.

예제 입력

[3, 6, 1, 8, 4, 7, 9, 2, 5]

예제 출력

[1, 2, 3, 4, 5, 6, 7, 8, 9]

코드 실행


    public class RadixSortExample {
        public static void main(String[] args) {
            int[] arr = {3, 6, 1, 8, 4, 7, 9, 2, 5};
            RadixSort.radixSort(arr);
            System.out.println("정렬된 배열: ");
            for (int num : arr) {
                System.out.print(num + " ");
            }
        }
    }
    

6. 마무리

이번 포스팅에서는 기수 정렬의 개념, 동작 방식, 자바 구현 및 문제 풀이 과정을 다뤄봤습니다. 기수 정렬은 제출 및 제출 기준에 따라 다양한 방법으로 응용될 수 있는 유용한 알고리즘입니다. 알고리즘 문제 풀이에서 기수 정렬을 자주 활용하시길 바라며, 다음에도 유익한 내용을 가지고 찾아오겠습니다. 감사합니다!

자바 코딩테스트 강좌, 그리디 알고리즘

자바 코딩테스트 강좌 – 그리디 알고리즘

그리디 알고리즘(Greedy Algorithm)은 우리가 알고 있는 최적화 문제에 대해 가장 최적의 선택을 차례차례로 선택해 나가는 방식입니다. 이 과정에서 매 단계마다의 최적 선택이 전체 문제에 대한 최적 해를 보장하지는 않지만, 많은 경우에 유용하게 사용됩니다. 이번 글에서는 그리디 알고리즘을 활용한 문제를 풀어보겠습니다.

문제: 동전 변경

문제 설명: 주어진 금액을 만들기 위해 필요한 최소 동전 개수를 구하는 프로그램을 작성하세요. 동전의 종류는 [500원, 100원, 50원, 10원] 대가 주어집니다.
예를 들어, 770원을 만들기 위해 필요한 최소 동전 개수를 구하세요.

입력

  • 정수 N (0 < N ≤ 10,000,000): 만들고자 하는 금액

출력

  • 정수 K: 필요한 최소 동전 개수

입력 예시

770

출력 예시

6

문제 접근 방법

문제를 해결하기 위해서는 주어진 동전의 종류를 고려하여 그리디 알고리즘을 적용합니다. 그리디 알고리즘의 핵심은 매 단계에서 가장 큰 가치를 가진 동전을 사용하는 것입니다. 주어진 동전의 종류가 정렬된 경우, 가장 큰 동전부터 사용하여 잔여 금액을 계속 줄여 나갈 수 있습니다.

코드 구현

이제 자바를 사용하여 문제를 해결하는 코드를 구현해 보겠습니다. 다음은 동전 변경 문제를 해결하는 자바 코드입니다.

import java.util.Scanner;

public class CoinChange {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // 주어진 금액을 입력받음
        int N = scanner.nextInt();
        
        // 사용할 동전의 종류
        int[] coins = {500, 100, 50, 10};
        
        int count = 0; // 동전 개수를 세기 위한 변수
        
        for (int coin : coins) {
            count += N / coin; // 현재 동전으로 만들 수 있는 개수 추가
            N %= coin;         // 잔여 금액 업데이트
        }
        
        System.out.println(count); // 최종 동전 개수 출력
        scanner.close();
    }
}

코드 설명

위의 코드에서는 다음과 같은 과정으로 최적의 해를 구합니다:

  1. 사용자 입력: Scanner 클래스를 사용하여 사용자가 만들고자 하는 금액을 입력받습니다.
  2. 패턴 설정: 사용할 동전의 배열을 정의합니다. 동전의 값은 내림차순으로 정리되어 있습니다.
  3. 동전 개수 계산: 각 동전에 대해 반복하여 가장 큰 동전부터 사용합니다. 현재 동전으로 몇 개를 사용할 수 있는지 계산하고, 잔여 금액을 업데이트합니다.
  4. 결과 출력: 최종적으로 필요한 동전의 개수를 출력합니다.

시간 복잡도

이 문제의 시간 복잡도는 O(1)입니다. 동전의 종류는 고정되어 있고, 입력된 금액에 관계 없이 상수 시간 내에 결과를 계산할 수 있습니다.

결론

그리디 알고리즘은 매 단계에서의 가장 최적의 선택을 통해 문제를 해결하는 방법입니다. 동전 변경 문제를 통해 그리디 알고리즘의 기본 원리를 이해하고, 이를 자바로 구현하는 방법에 대해 학습했습니다. 이 알고리즘은 다양한 최적화 문제에도 적용될 수 있으며, 알고리즘적 사고를 기르는 데 도움이 됩니다.

더 알아보기

그리디 알고리즘을 더욱 깊이 이해하기 위해, 다른 유형의 문제를 시도해 보시는 것을 추천합니다. 예를 들어, 혹은 최소 스패닝 트리(MST), 활동 선택 문제 등에서 그리디 알고리즘을 적용해 볼 수 있습니다.

부록

그리디 알고리즘은 다양한 문제를 해결하는 데 유용하게 사용될 수 있으며, 언젠가는 보다 복잡한 최적화 문제에 도전하게 될 것입니다. 실제 코딩 테스트에서는 문제를 정확히 읽고 그리디 알고리즘이 적합한지 판단하는 것이 중요합니다. 문제를 해결하는 데 필요한 수학적 사고와 자료 구조에 대한 이해를 함께 키워나가면 좋습니다.

자바 코딩테스트 강좌, 그래프의 표현

안녕하세요! 오늘은 자바를 사용하여 코딩테스트에 자주 출제되는 그래프의 표현에 대해 자세히 알아보고, 관련된 알고리즘 문제를 풀어보겠습니다. 그래프는 주어진 문제를 해결하는데 중요한 데이터 구조로, 정점(Vertex)과 간선(Edge)으로 구성됩니다. 우리는 여러 가지 방식으로 그래프를 표현할 수 있으며, 이번 글에서는 Adjacency List와 Adjacency Matrix 방식에 대해 설명하겠습니다.

그래프의 표현 방식

1. 인접 리스트(Adjacency List)

인접 리스트는 각 정점이 인접한 정점의 목록을 저장하는 방식입니다. 보통 배열이나 리스트를 사용하여 구현합니다. 이 방식은 메모리 효율성이 매우 뛰어나며, 다소 느리게 진행되는 연산에서도 유용합니다.

class Graph {
    private int vertices; // 정점의 수
    private LinkedList[] adjList; // 인접 리스트
    
    // 그래프 생성자
    public Graph(int v) {
        vertices = v;
        adjList = new LinkedList[v];
        for (int i = 0; i < v; i++) {
            adjList[i] = new LinkedList<>();
        }
    }

    // 간선 추가 메소드
    public void addEdge(int source, int destination) {
        adjList[source].add(destination);
        // 무방향 그래프인 경우, 다음 코드도 추가해야 합니다
        // adjList[destination].add(source);
    }
}

2. 인접 행렬(Adjacency Matrix)

인접 행렬은 2차원 배열을 사용하여 그래프를 표현하는 방식입니다. 이 방법은 간선이 존재하는지 여부를 O(1)의 시간 복잡도로 확인할 수 있지만, 공간 복잡도가 높고, 가변 크기의 그래프에서는 비효율적일 수 있습니다.

class Graph {
    private int vertices;
    private int[][] adjMatrix;

    // 그래프 생성자
    public Graph(int v) {
        vertices = v;
        adjMatrix = new int[v][v];
    }

    // 간선 추가 메소드
    public void addEdge(int source, int destination) {
        adjMatrix[source][destination] = 1;
        // 무방향 그래프인 경우
        // adjMatrix[destination][source] = 1;
    }
}

문제: 다리 만들기

이제 실제로 문제를 풀어보겠습니다. 주어진 문제는 다리 만들기입니다.

문제 설명

2D 평면에서 N개의 점이 주어지고, 모든 점이 서로 연결될 수 있도록 다리를 건설하고자 합니다.
다리의 길이는 두 점 사이의 유클리드 거리입니다.
가장 짧은 경로의 길이를 구하세요. 단, 다리를 건설하는 과정에서 같은 두 점을 다시 연결할 수 없습니다.

입력

  • 첫 번째 줄에 점의 개수 N(1 ≤ N ≤ 100) 이 주어집니다.
  • 두 번째 줄에 각 점의 좌표가 주어집니다. (x1, y1), (x2, y2), …, (xN, yN)

출력

가장 짧은 경로의 길이를 출력하시오. (소수점 아래 2자리까지)

문제 풀이 접근

문제를 해결하기 위해 다음과 같은 순서로 접근하겠습니다:

  1. 좌표를 입력받아 점들을 저장합니다.
  2. 좌표들 사이의 거리를 계산하여 다리 길이를 구합니다.
  3. Dijkstra 알고리즘을 사용하여 최단 경로를 구합니다.
  4. 결과를 소수점 둘째자리까지 출력합니다.

자바 코드 구현

import java.util.*;

class Point {
    int x, y;

    Point(int x, int y) {
        this.x = x;
        this.y = y;
    }

    double distance(Point p) {
        return Math.sqrt(Math.pow(this.x - p.x, 2) + Math.pow(this.y - p.y, 2));
    }
}

class Graph {
    private int vertices;
    private List points;
    private double[][] adjMatrix;

    public Graph(int v) {
        vertices = v;
        points = new ArrayList<>();
        adjMatrix = new double[v][v];
    }

    public void addPoint(Point p) {
        points.add(p);
        int idx = points.size() - 1;
        for (int i = 0; i < idx; i++) {
            double dist = points.get(i).distance(p);
            adjMatrix[i][idx] = dist;
            adjMatrix[idx][i] = dist; // 무방향 간선
        }
    }

    public double dijkstra() {
        double[] dist = new double[vertices];
        boolean[] visited = new boolean[vertices];

        Arrays.fill(dist, Double.MAX_VALUE);
        dist[0] = 0; // 시작점

        for (int i = 0; i < vertices - 1; i++) {
            int minIndex = findMinIndex(dist, visited);
            visited[minIndex] = true;

            for (int j = 0; j < vertices; j++) {
                if (!visited[j] && adjMatrix[minIndex][j] != 0 &&
                    dist[minIndex] + adjMatrix[minIndex][j] < dist[j]) {
                    dist[j] = dist[minIndex] + adjMatrix[minIndex][j];
                }
            }
        }

        return dist[vertices - 1]; // 끝점까지의 거리
    }

    private int findMinIndex(double[] dist, boolean[] visited) {
        double min = Double.MAX_VALUE;
        int minIndex = -1;
        for (int i = 0; i < vertices; i++) {
            if (!visited[i] && dist[i] < min) {
                min = dist[i];
                minIndex = i;
            }
        }
        return minIndex;
    }
}

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        Graph graph = new Graph(n);

        for (int i = 0; i < n; i++) {
            int x = sc.nextInt();
            int y = sc.nextInt();
            graph.addPoint(new Point(x, y));
        }

        double result = graph.dijkstra();
        System.out.printf("%.2f\n", result);
    }
}

결론

오늘은 그래프의 표현 방식과 함께 알고리즘 문제를 풀어보았습니다.
이 문제를 통해 그래프를 어떻게 다루는지, 인접 리스트와 인접 행렬을 활용하여 점 사이의 거리 계산 및 최단 경로 알고리즘을 구현하는 방법을 배웠습니다.
그래프는 실생활에서도 자주 사용되는 개념이며, 더 나아가 복잡한 문제를 해결하는 데 매우 유용합니다.

다음 시간에는 탐색 알고리즘과 관련된 내용을 살펴보도록 하겠습니다. 감사합니다!

자바 코딩테스트 강좌, 구간 합 구하기 3

안녕하세요! 오늘은 ‘구간 합 구하기 3’라는 주제로 자바 코딩테스트 문제를 함께 풀어보겠습니다. 이 문제는 주어진 배열에서 특정 구간의 합을 효율적으로 구하는 알고리즘을 구성하는 것을 목표로 합니다. 그러면 문제를 살펴보도록 하겠습니다.

문제 설명

주어진 정수 배열 Am개의 쿼리가 주어질 때, 각 쿼리는 두 개의 정수 XY로 나타내며, A[X] + A[X+1] + ... + A[Y]의 값을 출력하는 문제입니다. 단, 쿼리는 1-indexed입니다.

입력 형식

  • 첫 번째 줄에 두 개의 정수 N (배열 원소의 개수)과 M (쿼리의 개수)가 주어진다.
  • 둘째 줄에 N개의 정수로 이루어진 배열 A가 주어진다.
  • 셋째 줄부터 M개의 줄에 각각의 쿼리를 나타내는 두 개의 정수 XY가 주어진다.

출력 형식

각 쿼리의 결과를 한 줄에 하나씩 출력한다.

예제

입력 예제:
5 3
1 2 3 4 5
1 3
2 4
1 5

출력 예제:
6
9
15

문제 접근 방법

1-indexed 배열에서 특정 구간의 합을 구하기 위해서는 다음과 같은 방법을 사용할 수 있습니다:

  1. 우선 합 배열을 만든다: 원 배열의 합을 미리 계산하여 각 인덱스에서의 합을 저장하는 배열을 생성합니다. 이 합 배열을 사용하면 O(1) 시간 복잡도로 구간 합을 구할 수 있습니다.
  2. 구간 합 계산: 구간의 총 합은 sum[Y] - sum[X-1]로 계산할 수 있습니다. 여기서 sum[i]는 입력 배열의 1부터 i까지의 합입니다.

알고리즘 구현

자바로 알고리즘을 구현해 보겠습니다. 아래는 실제 코드입니다:

import java.util.Scanner;

public class IntervalSum {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        // 배열 크기 N과 쿼리 개수 M 입력 받기
        int N = scanner.nextInt();
        int M = scanner.nextInt();

        // 배열 A 선언 및 값 입력
        long[] A = new long[N + 1];
        for (int i = 1; i <= N; i++) {
            A[i] = scanner.nextLong();
        }

        // 합 배열 선언
        long[] sum = new long[N + 1];

        // 합 배열 생성
        for (int i = 1; i <= N; i++) {
            sum[i] = sum[i - 1] + A[i];
        }

        // 쿼리 처리
        for (int j = 0; j < M; j++) {
            int X = scanner.nextInt();
            int Y = scanner.nextInt();
            // 구간 합 계산 및 출력
            System.out.println(sum[Y] - sum[X - 1]);
        }

        // Scanner 닫기
        scanner.close();
    }
}

코드 설명

위 코드는 다음과 같은 구조로 되어 있습니다:

  1. Scanner를 사용하여 입력을 받습니다. 배열의 크기(N)와 쿼리의 개수(M)를 읽습니다.
  2. 배열 A를 만들고 1-indexed로 값을 할당합니다.
  3. 합 배열 sum을 생성합니다. 이 배열은 sum[i]가 배열 A의 1부터 i까지의 합을 저장합니다.
  4. 각 쿼리의 XY를 읽고 구간 합을 계산한 후 결과를 출력합니다.

시간 복잡도 분석

이 알고리즘의 시간 복잡도는 다음과 같습니다:

  • 합 배열을 만드는 데 O(N) 시간이 소요됩니다.
  • 각 쿼리를 처리하는 데 O(1)의 시간이 소요됩니다. 따라서 쿼리 M에 대해 O(M)의 시간이 소요됩니다.

결론적으로, 전체 알고리즘의 시간 복잡도는 O(N + M)입니다. 이는 문제를 효율적으로 해결할 수 있는 방법입니다.

마무리

오늘은 ‘구간 합 구하기 3’ 문제를 통해 Java 언어로 알고리즘 문제를 해결하는 방법을 배워보았습니다. 합 배열을 활용하여 쿼리의 효율성을 높이는 방법에 대해 이해하셨기를 바랍니다. 추가적인 문제를 통해 더 많은 연습을 해보세요. 다음 강좌에서는 다른 주제로 찾아뵙겠습니다. 감사합니다!