Algorithm

Algorithm | 구간 합 구하기 (백준 11659번)

Code & Beyond 2025. 5. 2. 14:37

문제

수 N개가 주어졌을 때, i번째 수부터 j번째 수까지 합을 구하는 프로그램을 작성하시오.

 

입력

첫째 줄에 수의 개수 N과 합을 구해야 하는 횟수 M이 주어진다. 둘째 줄에는 N개의 수가 주어진다. 수는 1,000보다 작거나 같은 자연수이다. 셋째 줄부터 M개의 줄에는 합을 구해야 하는 구간 i와 j가 주어진다.

 

출력

총 M개의 줄에 입력으로 주어진 i번째 수부터 j번째 수까지 합을 출력한다.

 

 

제한

  • 1 ≤ N ≤ 100,000
  • 1 ≤ M ≤ 100,000
  • 1 ≤ i ≤ j ≤ N

 

 

예제 입력

5 3
5 4 3 2 1
1 3
2 4
5 5

 

예제 출력

12
9
1

 

풀이1

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.StringTokenizer;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
        StringTokenizer stringTokenizer = new StringTokenizer(bufferedReader.readLine());

        int n = Integer.parseInt(stringTokenizer.nextToken()); // 숫자 개수
        int m = Integer.parseInt(stringTokenizer.nextToken()); // 질의 개수

        long[] prefixSum = new long[n + 1]; // 구간 합 배열 (1-based index)

        // 숫자들 입력 받고 구간합 배열 만들기
        stringTokenizer = new StringTokenizer(bufferedReader.readLine());
        for (int i = 1; i <= n; i++) {
            prefixSum[i] = prefixSum[i - 1] + Integer.parseInt(stringTokenizer.nextToken());
        }

        // 질의 처리
        for (int q = 0; q < m; q++) {
            stringTokenizer = new StringTokenizer(bufferedReader.readLine());
            int start = Integer.parseInt(stringTokenizer.nextToken()); // i
            int end = Integer.parseInt(stringTokenizer.nextToken()); // j
            System.out.println(prefixSum[end] - prefixSum[start - 1]);
        }
    }
}

 

풀이2

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();  // 숫자 개수 N
        int m = sc.nextInt();  // 질의 개수 M

        int[] prefixSum = new int[n + 1];  // 인덱스를 1부터 사용하기 위해 크기 n+1

        // 구간마다의 누적합 배열 만들기
        for (int i = 1; i <= n; i++) {
            int num = sc.nextInt();
            prefixSum[i] = prefixSum[i - 1] + num;
        }

        // 구간합 질의 처리
        for (int i = 0; i < m; i++) {
            int start = sc.nextInt();
            int end = sc.nextInt();
            System.out.println(prefixSum[end] - prefixSum[start - 1]);
        }

        sc.close();
    }
}

 

 두 풀이 모두 어떤 유틸 객체로 입력값을 변환했는지 차이일 뿐, 풀이 과정에 대한 본질적인 차이는 없다. 1번 풀이 방법이 입력값을 읽는 데에 좀 더 성능상 효율적이다. 백준에서도 풀이방법1은 메모리 60476KB, 시간 1104ms이고, 2는 메모리 256588KB, 시간 1828ms이다. 시간 상으로는 600-700ms 차이라도 메모리 효율이 4배이상 좋다.

 숫자 개수 N 만큼의 크기로 prefixSum을 만들어도 되지만 구간합 질의 처리에서 구간이 배열 인덱스 형태로 나오지 않기 때문에 편의상 n+1로 크기를 설정하게 되었다. 미리 구간마다의 누적합을 구하면 답을 처리할 때, j까지 의 구간합에서 i까지의 구간합을 마이너스하면 답이 출력된다.

 

 

 

참고

Do it! 알고리즘 코딩 테스트 - 자바편