ALGORITHM NOTE1

BOJ 11659 - 구간 합 구하기 4

한 번에 모아 두면 구간 계산이 뚝딱

#algorithm#boj#silver#prefix-sum
아카이브로 돌아가기

문제 링크

문제

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

입력

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

출력

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

풀이

구간 합을 여러 번 물어보는 문제라서, 매번 직접 더하면 시간 내에 끝나기 어렵다. 그래서 먼저 누적합을 만들어 두고 각 질문을 상수 시간에 처리해야 한다.

현재 구현은 1차원 누적합을 사용한다. numbers[i]에 1번째 수부터 i번째 수까지의 합을 저장해 두면, 구간 [i, j]의 합은 numbers[j] - numbers[i - 1]로 바로 구할 수 있다.

쿼리마다 같은 구간을 다시 순회하지 않는 것이 핵심이다. 한 번 만든 누적합 배열은 이후 모든 질의를 뺄셈 한 번으로 바꿔 준다.

코드

java
import java.io.*;
import java.util.*;
 
public class Main {
 
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        StringTokenizer st = new StringTokenizer(br.readLine());
 
        int N = Integer.parseInt(st.nextToken());
        int M = Integer.parseInt(st.nextToken());
 
        int[] numbers = new int[N + 1];
        st = new StringTokenizer(br.readLine());
        for (int i = 1; i <= N; i++)
            numbers[i] = numbers[i - 1] + Integer.parseInt(st.nextToken());
 
        while (M-- > 0) {
            st = new StringTokenizer(br.readLine());
            int i = Integer.parseInt(st.nextToken());
            int j = Integer.parseInt(st.nextToken());
            sb.append(numbers[j] - numbers[i - 1]).append('\n');
        }
 
        System.out.println(sb);
    }
}

복잡도

  • 시간 복잡도: 누적합 전처리 O(N)O(N), 질의 처리 O(M)O(M)이므로 전체 O(N+M)O(N + M)이다.
  • 공간 복잡도: 누적합 배열을 저장하므로 O(N)O(N)이다.

마무리

누적합 하나만 만들어 두면 구간 합 질의는 뺄셈 한 번으로 정리된다.