N개의 수가 주어질 때,
여러 개의 구간 [i, j]에 대해
i번째부터 j번째까지의 합
을 구하는 문제이다.
첫째 줄
N M
둘째 줄
N개의 수
셋째 줄부터 M개의 줄
i j
조건
1 ≤ N, M ≤ 100,000
각 구간에 대해 합을 출력한다.
5 3
5 4 3 2 1
1 3
2 4
5 5
12
9
1
이 문제의 핵심은 다음이다.
누적합(prefix sum)
매번 구간 합을 직접 계산하면
O(N)
이 걸린다.
M번 반복하면
O(N × M)
→ 시간초과
누적합 배열을 만들면
구간합 = acc[j] - acc[i-1]
으로 한 번에 계산 가능
나는 입력을 받으면서 누적합을 바로 계산했다.
import java.util.*;
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int M = sc.nextInt();
int[] nums = new int[N];
int sum = 0;
for(int i = 0; i < N; i++) {
sum += sc.nextInt();
nums[i] = sum;
}
for(int j = 0; j < M; j++) {
int start = sc.nextInt();
int end = sc.nextInt();
if(end == 1 && start == end) {
System.out.println(nums[end-1]);
}
else if(start != 1) {
System.out.println(nums[end-1] - nums[start-2]);
}
else {
System.out.println(nums[end-1]);
}
}
}
}
강의에서는 누적합 배열을 따로 만들어 더 간단하게 처리했다.
import java.util.Scanner;
class Main
{
public static void main (String[] args) {
Scanner sc = new Scanner(System.in);
int N = sc.nextInt();
int M = sc.nextInt();
int[] arr = new int[N + 1];
for (int i = 1; i <= N; i++)
arr[i] = sc.nextInt();
int[] acc = new int[N + 1];
for (int i = 1; i <= N; i++)
acc[i] = acc[i - 1] + arr[i];
while (M-- > 0) {
int i = sc.nextInt();
int j = sc.nextInt();
System.out.println(acc[j] - acc[i - 1]);
}
}
}
0번부터 시작 (0-index)
nums[i] = sum;
1번부터 시작 (1-index)
acc[i] = acc[i-1] + arr[i];
| 방식 | 특징 |
|---|---|
| 내 코드 | 0-index 기반 |
| 강의 코드 | 1-index 기반 |
if(start != 1)
nums[end-1] - nums[start-2]
→ 조건 분기 필요
acc[j] - acc[i - 1]
→ 조건 없이 처리 가능
내 코드 → 조건 분기 필요
강의 코드 → 조건 없이 계산 가능
if문 여러 개 필요
한 줄로 처리
강의 코드 방식이 더 많이 사용된다.
이유
1-index 사용 → 실수 줄어듦
조건문 제거 → 코드 간결
acc[i] = acc[i-1] + arr[i]
i ~ j = acc[j] - acc[i-1]
전체
O(N + M)
이 문제는 대표적인 누적합 문제이다.
내 코드는 누적합을 직접 만들었지만
조건 처리가 많아 코드가 복잡해졌다.
강의 코드는
1-index 누적합
을 사용해서 더 깔끔하게 해결했다.
핵심 차이는 다음과 같다.
내 코드 → 조건 분기 기반 계산
강의 코드 → 공식 기반 계산
즉, 이 문제는
누적합 공식을 제대로 이해하는 것이 핵심
인 문제였다.