저번시간에는 투 포인터
에 대해 알아보았다.
이번시간에는 구간 합 계산
에 대해 알아보자.
Prefix_sum(구간 합)
: 연속적으로 나열된 N
개의 수가 있을 때, 특정 구간의 모든 수를 합한 값을 구하는 문제각 쿼리에 대해 구간합을 빠르게 계산하기 위해서는 N개의 수의 위치 각각에 대하여 접두사 합을 미리 구해 놓으면 된다.
여기서 접두사 합이란 리스트의 맨 앞부터 특정 위치까지의 합을 구해 놓은 것을 말한다.
예를 들어 5개의 데이터 구성된 수열 {10, 20, 30, 40, 50}
이 있다고 가정해보자.
여기서 2번째 수부터 4번째 수까지의 합은 20 + 30 + 40으로 90이 될 것이다.
구간 합 계산 문제는 여러 개의 쿼리(Query)
로 구성되는 문제 형태로 출제되는 경우가 많다.
예를 들어, M개의 쿼리가 존재한다고 가정해보자.
각 쿼리는 Right
, Left
로 구성되며, 이는 [Left, Right]
의 구간을 의미한다.
결과적으로 쿼리가 주어졌을 때, 모든 쿼리에 대하여 구간의 합을 출력하는 문제가 전형적인 구간 합 계산
문제이다.
만약, M
개의 쿼리 각각, 매번 구간 합을 계산하면 이러한 알고리즘은 O(NM)
시간 복잡도를 가진다.
왜냐하면, M
개의 쿼리가 수행될 때마다 전체 리스트의 구간 합을 모두 계산하라고 요구(첫 번째 수부터 N번째 수까지) 할 수 있기 때문이다.
알고리즘이 O(NM)
시간 복잡도를 가지게 되면 데이터 개수가 매우 많을 때 시간초과
로 문제를 해결 할 수 없을 것이다.
항상 우리가 알고리즘을 설계할때 고려할 점 다음과 같다.
여러 번 사용될 만한 정보는 미리 구해 저장해 놓을수록 유리하다.
또, 쿼리는 M
개 이지만, N
개의 수는 한 번 주어진 뒤에 변경되지 않는다.
따라서, N
개의 수에 대해 어떠한 처리를 수행 한 뒤에 나중에 M개의 쿼리가 각각 주어 질때마다 빠르게 구간합을 구하면 어떨까?
구간 합 알고리즘의 순서는 다음과 같다.
N
개의 수에 대해접두사 합(Prefix Sum)
을 계산하여 배열 P에 저장한다.- 매
M
개의 쿼리 정보[L, R]
을 확인 할 때, 구간 합은P[R] - P[L-1]
이다.- 만약 1~3까지의 구간 합을 구하면
P[3] - P[0]
가 된다.- 만약 2~4까지의 구간 합을 구하면
P[4] - P[1]]
가 된다.
이와 같은 순서로 알고리즘을 처리하면 P[R] - P[L-1]
식만 가지고도 문제를 해결 할 수 있다.
따라서 매 쿼리당 계산 시간은 O(1)
이 된다. 결과적으로 모두 계산하는 작업은 O(N+M)
의 시간복잡도를 가진다.
n = 5
data = [10, 20, 30, 40, 50]
value_sum = 0
prefix_sum = [0]
for i in data:
value_sum = value_sum + i
prefix_sum.append(value_sum)
left = 3
right = 4
result = prefix_sum[right] - prefix_sum[left - 1]
print(result)
👉🏽 70
예제를 풀어봤다.
구간 합 계산파트는 구현했으나, 입력값을 어떻게 작성해야할지 몰라 헤맸다.
많은 시간 끝에 문제를 해결 할 수 있었다.
sys.stdin.readline().split()
의 응용법도 깨달았다.
input()
으로 변수를 입력 받는다.for()
문을 작성해input()
으로 입력받은 만큼만data_input
을 생성한다.
예)input()
이 5면data_input
도 4개의 리스트([10, 20, 30, 40, 50]) 선언- 구간 설정값은
left
,right
값으로 빼내서 계산
import sys
n, m = map(int, input().split())
data_input = list(map(int, sys.stdin.readline().split()))
value = 0
prefix_sum = [0]
for i in data_input:
value = value + i
prefix_sum.append(value)
for i in range(m):
left, right = map(int, sys.stdin.readline().split())
result = prefix_sum[right] - prefix_sum[left - 1]
print(result)
매일매일 알고리즘을 풀려고 노력하니까 점점 코딩에 나름(?) 자신감이 붙는것 같다.
아직은 매우 부족하지만 나중에는 문제만 봐도 알고리즘을 척척 만들 수 있는 개발자가 됐으면 좋겠다.
내일부터는 2020년이 아닌 2021년이다.
나이를 한살 더 먹는 만큼 내 인생도 한층 성숙해졌으면 좋겠다.
그럼 20000...