파이썬 코딩테스트 강좌, 기수 정렬

안녕하세요! 오늘은 파이썬에서 기수 정렬(Radix Sort) 알고리즘에 대해 알아보겠습니다. 기수 정렬은 공간 복잡도와 시간 복잡도가 매우 유리한 정렬 알고리즘 중 하나로, 특히 정수나 문자열과 같은 형태의 데이터를 정렬할 때 유용합니다. 이 강좌에서는 기수 정렬의 원리, 구현 방법, 그리고 실제 문제를 통해 기수 정렬을 사용하는 방법을 자세히 설명하겠습니다.

기수 정렬이란?

기수 정렬은 주어진 숫자의 각 자리수(십의 자리, 백의 자리 등)를 고려하여 정렬하는 방법입니다. 기수 정렬은 다음과 같은 단계로 진행됩니다:

  1. 가장 낮은 자리수부터 시작하여 각 자리수를 기준으로 분배합니다.
  2. 분배된 수들을 다시 모아서 정렬된 리스트를 만듭니다.
  3. 다음 자리수로 이동하여 과정을 반복합니다.

기수 정렬은 일반적으로 두 가지 방식으로 구현됩니다: LSD(Least Significant Digit) 방식과 MSD(Most Significant Digit) 방식. 이 강좌에서는 LSD 방식, 즉 가장 작은 자리수부터 시작하는 기수 정렬에 초점을 맞출 것입니다.

기수 정렬의 시간 복잡도

기수 정렬의 시간 복잡도는 O(nk)입니다. 여기서 n은 정렬할 숫자의 개수, k는 가장 큰 수의 자리수입니다. 기수 정렬은 안정 정렬로 분류되며, 이는 같은 값을 가진 요소의 상대적인 순서가 변하지 않음을 의미합니다.

문제: 기수 정렬을 이용한 정렬

이제 기수 정렬을 적용하여 주어진 정수를 정렬하는 문제를 풀어보겠습니다. 문제는 다음과 같습니다:

문제 설명

정수의 배열이 주어질 때, 기수 정렬을 사용하여 이 배열을 오름차순으로 정렬하는 프로그램을 작성하세요.

입력

  • 정수의 배열: [170, 45, 75, 90, 802, 24, 2, 66]

출력

오름차순으로 정렬된 배열을 출력하세요.

문제 풀이 과정

이제 위의 문제를 해결하기 위해 기수 정렬을 구현해보겠습니다. 먼저, 아래와 같이 각 자리수를 기준으로 정렬하는 보조 함수인 counting_sort를 작성하겠습니다. 이 함수는 주어진 자리수를 기준으로 배열을 정렬합니다.

def counting_sort(arr, exp):
    n = len(arr)
    output = [0] * n  # 정렬된 배열을 저장할 리스트
    count = [0] * 10  # 0~9까지의 숫자를 세기 위한 리스트

    # 현재 자리수에 따라 각 숫자의 개수를 센다
    for i in range(n):
        index = (arr[i] // exp) % 10
        count[index] += 1

    # 누적합을 통해 각 숫자의 위치를 찾는다
    for i in range(1, 10):
        count[i] += count[i - 1]

    # 정렬된 배열을 생성
    for i in range(n - 1, -1, -1):
        index = (arr[i] // exp) % 10
        output[count[index] - 1] = arr[i]
        count[index] -= 1

    # 정렬된 결과를 원본 배열에 반영
    for i in range(n):
        arr[i] = output[i]

위의 코드에서 counting_sort 함수는 입력 배열에서 각 숫자의 현재 자리수를 검사하여 해당 자리수에 맞는 숫자의 개수를 카운트하고, 누적 합을 통해 정렬된 결과를 생성합니다. 이제 기수 정렬을 구현하는 메인 함수를 작성하겠습니다.

def radix_sort(arr):
    # 배열에서 가장 큰 수를 찾아 자리수를 결정
    max_num = max(arr)

    # 가장 작은 자리수부터 시작하여 정렬
    exp = 1
    while max_num // exp > 0:
        counting_sort(arr, exp)
        exp *= 10

이제 기수 정렬의 전체 구현을 살펴보겠습니다.

def radix_sort(arr):
    max_num = max(arr)  # 최대값을 찾는다
    exp = 1  # 자리수의 승수 초기화
    while max_num // exp > 0:  # 최대값의 자리수 만큼 반복
        counting_sort(arr, exp)  # 현재 자리수에 대해 counting_sort 호출
        exp *= 10  # 다음 자리수로 이동

def counting_sort(arr, exp):
    n = len(arr)
    output = [0] * n  # 정렬된 배열을 저장할 리스트
    count = [0] * 10  # 0~9까지의 숫자를 세기 위한 리스트

    # 현재 자리수에 따라 각 숫자의 개수를 센다
    for i in range(n):
        index = (arr[i] // exp) % 10
        count[index] += 1

    # 누적합을 통해 각 숫자의 위치를 찾는다
    for i in range(1, 10):
        count[i] += count[i - 1]

    # 정렬된 배열을 생성
    for i in range(n - 1, -1, -1):
        index = (arr[i] // exp) % 10
        output[count[index] - 1] = arr[i]
        count[index] -= 1

    # 정렬된 결과를 원본 배열에 반영
    for i in range(n):
        arr[i] = output[i]

# 테스트 코드
arr = [170, 45, 75, 90, 802, 24, 2, 66]
print("정렬 전 배열:", arr)
radix_sort(arr)
print("정렬 후 배열:", arr)

테스트 결과

위의 코드를 실행하면 다음과 같은 결과가 나타납니다:

정렬 전 배열: [170, 45, 75, 90, 802, 24, 2, 66]
정렬 후 배열: [2, 24, 45, 66, 75, 90, 170, 802]

정렬 전의 배열과 정렬 후의 배열을 비교하면, 기수 정렬이 잘 작동한 것을 알 수 있습니다.

기수 정렬의 장점과 단점

장점

  • 특정한 조건의 데이터(정수, 문자열 등)에 대해 매우 빠른 성능을 발휘합니다.
  • 안정 정렬이기 때문에 같은 값을 가진 요소들의 순서가 보존됩니다.
  • 특정 자리수에 관심이 있는 경우 효율적으로 정렬이 가능합니다.

단점

  • 메모리를 추가로 소비하며, 원본 배열과 동일한 크기의 배열이 필요합니다.
  • 정수나 문자열이 아닌 다른 데이터 타입에는 적합하지 않습니다.
  • 데이터의 범위가 매우 큰 경우 시간 복잡도가 증가할 수 있습니다.

마무리

이번 강좌에서는 기수 정렬에 대해 자세히 알아보았고, 이를 통해 배열을 정렬하는 문제를 해결했습니다. 기수 정렬은 특정한 상황에서 매우 유용한 정렬 알고리즘이므로, 알고리즘 시험에서는 자주 등장할 수 있습니다. 따라서, 기수 정렬의 원리와 실제 구현 방법을 명확히 이해하는 것이 중요합니다. 다음 시간에는 또 다른 유용한 정렬 알고리즘이나 데이터 구조에 대해 알아보도록 하겠습니다. 읽어주셔서 감사합니다!

파이썬 코딩테스트 강좌, 그리디 알고리즘

문제 설명

오늘 다룰 문제는 동전 거스름돈 문제입니다. 이 문제는 우리가 현실에서 자주 접하는 다양한 동전을 이용해 특정 금액을 만들 때, 가장 적은 수의 동전을 사용하는 방법을 찾는 것입니다.

문제 정의

다음과 같은 조건을 만족하는 함수 min_coins(coins, amount)를 작성하시오:

  • coins: 사용 가능한 동전의 목록 (예: [1, 5, 10, 25])
  • amount: 만들고자 하는 금액

이 함수는 주어진 금액을 만들기 위해 필요한 최소 동전의 수를 반환해야 합니다. 동전을 사용할 수 없는 경우에는 -1을 반환합니다.

문제 이해하기

문제를 좀 더 깊이 있게 이해하기 위해 몇 가지 예제를 살펴보겠습니다.

예제 1:
입력: coins = [1, 5, 10, 25], amount = 63
출력: 6
설명: 25 + 25 + 10 + 1 + 1 + 1 = 63
예제 2:
입력: coins = [2, 4], amount = 5
출력: -1
설명: 5를 만들 수 있는 방법이 없음.

접근 방법

이 문제를 해결하기 위해 그리디 알고리즘을 사용하겠습니다. 그리디 알고리즘은 현재 상황에서 가장 최적인 선택을 하는 방식으로 동작합니다. 따라서, 우리는 가장 큰 동전부터 차례대로 사용하여 목표 금액을 만드는 방법을 모색하려 합니다.

해당 알고리즘의 구체적인 단계는 다음과 같습니다:

  1. 사용 가능한 동전들을 내림차순으로 정렬합니다.
  2. 현재 금액을 동전과 비교하여 가능한 한 많은 동전을 사용합니다.
  3. 남은 금액이 0이 될 때까지 이 과정을 반복합니다.
  4. 남은 금액이 0이 되었을 경우 동전의 개수를 반환하고, 그렇지 않을 경우 -1을 반환합니다.

코드 구현

그럼 이 접근 방법을 바탕으로 코드를 작성해보겠습니다:


def min_coins(coins, amount):
    # 동전을 내림차순으로 정렬
    coins.sort(reverse=True)
    
    count = 0  # 사용한 동전의 수
    
    for coin in coins:
        # 현재 동전이 amount보다 큰 경우 무시
        while amount >= coin:
            amount -= coin  # 동전의 가치를 amount에서 빼기
            count += 1  # 동전 개수 증가
            
    # 최종적으로 amount가 0인지 확인
    return count if amount == 0 else -1
    

테스트

이제 작성한 함수를 테스트해보겠습니다.


# 테스트 케이스
print(min_coins([1, 5, 10, 25], 63))  # 6
print(min_coins([2, 4], 5))             # -1
print(min_coins([5, 2, 1], 11))         # 3 (5 + 5 + 1)
    

결론

이러한 방식으로 그리디 알고리즘을 사용하여 동전 거스름돈 문제를 해결할 수 있었습니다. 이 문제를 통해 그리디 알고리즘의 기초적인 접근 방식을 익히고, 코딩 테스트에서 흔히 나오는 문제 유형을 공부했습니다.

앞으로 더 많은 문제를 연습하며 그리디 알고리즘에 대한 이해를 깊이게 쌓아가길 바랍니다. 위의 문제와 같이, 데이터를 어떻게 정렬하고, 반복문을 활용하여 해결책을 찾아나가는지에 대한 연습이 필요합니다. 그리디 알고리즘은 다양한 문제 해결에 유용한 도구가 될 수 있습니다.

감사합니다!

파이썬 코딩테스트 강좌, 그래프의 표현

그래프는 수학적 객체로, 정점(Vertex)와 간선(Edge)로 구성됩니다.
그래프는 데이터 구조에서 핵심적인 역할을 하며, 여러 복잡한 문제를 해결하는 데 효율적인 방식입니다.
이 글에서는 그래프의 기본 개념을 설명하고, 파이썬을 사용하여 그래프를 표현하고 탐색하는 방법을 다룰 것입니다.

1. 그래프의 기본 개념

그래프는 노드와 그 노드를 연결하는 간선으로 이루어져 있습니다. 그래프는 다음과 같은 두 가지 형태로 구분할 수 있습니다:

  • 유향 그래프 (Directed Graph): 간선이 방향성을 가진 그래프입니다. 즉, 간선이 A에서 B로 향할 때, B에서 A로의 간선은 존재하지 않을 수 있습니다.
  • 무향 그래프 (Undirected Graph): 간선이 방향성을 가지지 않는 그래프입니다. A와 B가 연결된 간선은 양방향으로 존재합니다.

2. 그래프의 표현 방법

그래프는 여러 가지 방법으로 표현할 수 있습니다. 가장 일반적인 방법은 다음과 같습니다:

  1. 인접 리스트 (Adjacency List): 각 정점에 연결된 정점의 리스트를 유지하여 그래프를 표현합니다. 이 방법은 메모리 사용이 효율적입니다.
  2. 인접 행렬 (Adjacency Matrix): 그래프의 모든 정점을 행렬 형태로 표현합니다. 행렬의 각 원소는 두 정점 간의 연결 여부를 나타냅니다.

3. 문제 풀이: 그래프의 표현

이제 그래프를 표현하는 실제 문제를 풀어보겠습니다.

문제 설명

정점의 개수와 간선의 정보를 입력받아, 주어진 정보를 바탕으로 그래프를 인접 리스트와 인접 행렬 형태로 표현하는 프로그램을 작성하시오.

입력 형식:

  • 첫 번째 줄에 정점의 개수 N (1 ≤ N ≤ 100)이 주어진다.
  • 두 번째 줄에 간선의 개수 M (1 ≤ M ≤ 1000)이 주어진다.
  • 세 번째 줄부터 M개의 줄에 걸쳐 간선의 정보 (A, B)가 주어진다. A와 B는 1에서 N까지의 정수이며, A와 B가 연결되어 있음을 나타낸다.

출력 형식:

첫 번째 줄에 인접 리스트, 두 번째 줄에 인접 행렬을 출력하시오. 각 정점은 1부터 시작한다.

4. 문제 해결 과정

위 문제를 해결하기 위해 풀어야 할 단계는 다음과 같습니다:

4.1. 입력 처리

먼저, 사용자로부터 정점과 간선 정보를 입력받습니다. 파이썬의 input() 함수를 사용하여 입력을 받고, 이를 적절한 형태로 변환합니다.

4.2. 인접 리스트 생성

인접 리스트는 리스트의 리스트를 사용하여 각 정점에 연결된 정점들을 저장합니다. 이때, 정점의 번호는 1부터 시작하므로 리스트의 인덱스와 맞추기 위해 미리 빈 리스트를 추가합니다.

4.3. 인접 행렬 생성

인접 행렬은 2차원 배열을 사용하여 정점 간의 연결 여부를 저장합니다. 초기값은 0으로 설정하고, 간선이 존재하는 경우에는 1로 설정합니다. 무향 그래프인 경우 A-B의 연결이 있을 때, 행렬의 (A, B)와 (B, A) 모두 업데이트해야 합니다.

4.4. 결과 출력

마지막으로, 생성된 인접 리스트와 인접 행렬을 출력합니다.

5. 코드 구현

def graph_representation():
    # 입력 받기
    N = int(input("정점의 개수를 입력하세요 (1 ≤ N ≤ 100): "))
    M = int(input("간선의 개수를 입력하세요 (1 ≤ M ≤ 1000): "))
    
    # 인접 리스트 초기화
    adj_list = [[] for _ in range(N + 1)]
    
    # 인접 행렬 초기화
    adj_matrix = [[0] * (N + 1) for _ in range(N + 1)]
    
    # 간선 정보 입력
    for _ in range(M):
        A, B = map(int, input("간선 정보를 입력하세요 (A B): ").split())
        adj_list[A].append(B)
        adj_list[B].append(A)  # 무향 그래프
        adj_matrix[A][B] = 1
        adj_matrix[B][A] = 1  # 무향 그래프
    
    # 인접 리스트 출력
    print("인접 리스트:")
    for i in range(1, N + 1):
        print(f"{i}: {adj_list[i]}")
    
    # 인접 행렬 출력
    print("인접 행렬:")
    for i in range(1, N + 1):
        print(" ".join(map(str, adj_matrix[i][1:])))
        
# 함수 호출
graph_representation()

6. 코드 설명

위 Python 코드는 아래의 절차로 구성되어 있습니다:

  • 입력 처리: 정점과 간선의 개수를 입력받고, 각 간선에 대한 정보를 입력받습니다.
  • 인접 리스트 초기화: 정점의 개수 N에 맞춰 빈 리스트를 생성합니다.
  • 인접 행렬 초기화: N x N 크기의 행렬을 0으로 초기화합니다.
  • 간선 정보 입력 및 리스트/행렬 업데이트: 반복문을 통해 입력받은 A, B에 따라 인접 리스트와 행렬을 업데이트합니다.
  • 결과 출력: 인접 리스트와 인접 행렬을 각각 출력합니다.

7. 실행 예시

예를 들어, 5개의 정점과 6개의 간선이 있는 그래프의 경우 입력과 출력은 다음과 같습니다:

정점의 개수를 입력하세요 (1 ≤ N ≤ 100): 5
간선의 개수를 입력하세요 (1 ≤ M ≤ 1000): 6
간선 정보를 입력하세요 (A B): 1 2
간선 정보를 입력하세요 (A B): 1 3
간선 정보를 입력하세요 (A B): 2 4
간선 정보를 입력하세요 (A B): 3 4
간선 정보를 입력하세요 (A B): 4 5
간선 정보를 입력하세요 (A B): 2 5
인접 리스트:
1: [2, 3]
2: [1, 4, 5]
3: [1, 4]
4: [2, 3, 5]
5: [2, 4]
인접 행렬:
0 1 1 0 0
1 0 0 1 1
1 0 0 1 0
0 1 1 0 1
0 1 0 1 0

8. 마무리

이번 강좌에서는 그래프의 개념과 다양한 표현 방법을 알아보았습니다. 문제를 통해 인접 리스트와 인접 행렬을 생성하는 방법도 배웠고, 이를 실제로 구현함으로써 그래프의 기본 구조를 이해할 수 있었습니다. 그래프 탐색(DFS, BFS) 등 더 나아가 해결해야 할 문제들이 많으니, 이를 토대로 다음 단계로 나아가기를 바랍니다.

알고리즘 공부를 하며 다양한 그래프 문제를 풀어보세요. 감사합니다!

파이썬 코딩테스트 강좌, 구간 합 구하기 3

문제 설명

주어진 정수 배열 A와 여러 쌍의 정수 L, R이 주어졌을 때, 각 쌍에 대해 L번 인덱스부터 R번 인덱스의 구간 합을 구하는 프로그램을 작성하시오.

예를 들어, A = [1, 2, 3, 4, 5]이고 구간 쌍이 (1, 3), (0, 2), (2, 4)라고 하면,
결과는 각각 9, 6, 12가 되어야 합니다.

입력 형식

    - 첫 줄에 정수 N (1 ≤ N ≤ 100,000): 배열 A의 크기
    - 둘째 줄에는 N개의 정수 A[i] (1 ≤ A[i] ≤ 10,000)가 주어진다.
    - 셋째 줄에 정수 M (1 ≤ M ≤ 100,000): 구간 쌍의 개수
    - 이어서 M줄에 걸쳐 구간 쌍 L, R (0 ≤ L <= R < N)가 주어진다.
    

출력 형식

    - 각 구간의 합을 M줄에 걸쳐 출력한다.
    

문제 해결 전략

이 문제를 해결하기 위해서는 단순히 반복문을 사용하는 것도 가능하지만,
최악의 경우 N과 M이 최대 100,000이므로 O(N * M)의 시간 복잡도를 가진 연산은 불가능하다.
따라서 O(N + M)의 시간 복잡도를 가지는 방법이 필요하다.

이를 위해 전처리 과정으로 누적 합 배열을 만들어 주면 유용하다.
누적 합 배열을 이용하면 각 구간의 합을 빠르게 구할 수 있다.

누적 합 배열 설명

먼저 배열 A의 누적 합을 계산하여 prefix_sum 배열을 생성한다.
prefix_sum[i]는 A[0]부터 A[i]까지의 합을 저장한다.
그러면 L번 인덱스부터 R번 인덱스의 합은 다음과 같이 계산할 수 있다:

sum(L, R) = prefix_sum[R] – prefix_sum[L – 1], L > 0

sum(0, R) = prefix_sum[R], L = 0

코드 구현

    
def compute_prefix_sum(A):
    prefix_sum = [0] * len(A)
    prefix_sum[0] = A[0]
    for i in range(1, len(A)):
        prefix_sum[i] = prefix_sum[i - 1] + A[i]
    return prefix_sum

def range_sum(prefix_sum, L, R):
    if L == 0:
        return prefix_sum[R]
    else:
        return prefix_sum[R] - prefix_sum[L - 1]

def main():
    N = int(input())
    A = list(map(int, input().split()))
    M = int(input())
    
    prefix_sum = compute_prefix_sum(A)

    results = []
    for _ in range(M):
        L, R = map(int, input().split())
        results.append(range_sum(prefix_sum, L, R))
    
    for result in results:
        print(result)

if __name__ == "__main__":
    main()
    
    

코드 설명

1. compute_prefix_sum 함수는 입력받은 배열 A의 누적 합을 계산하여
prefix_sum 배열을 반환합니다. 초기값을 설정하고, 각 인덱스의 값은 이전 값과 현재 값을 더하여 계산합니다.

2. range_sum 함수는 주어진 L과 R에 대해 누적 합 배열을 사용하여
구간의 합을 빠르게 계산합니다. L이 0이면 prefix_sum[R]을 반환하고, 그렇지 않으면
prefix_sum[R]에서 prefix_sum[L-1]을 빼서 결과를 계산합니다.

3. main 함수에서는 입력을 처리하고, 각 구간 쌍에 대해 range_sum 함수를 호출하여
결과를 출력합니다.

시간 복잡도 분석

– 누적 합 배열을 계산하는 데 O(N)의 시간이 걸립니다.

– 각 M개의 쿼리에 대해 O(1)의 시간이 소요됩니다.
따라서 전체적으로 O(N + M)의 시간 복잡도를 가집니다.

결론

이번 강좌에서는 구간 합 구하기에 대한 효율적인 접근 방법을 다루었습니다.
누적 합을 활용하면 시간 복잡도를 줄일 수 있어 큰 입력에도 빠르게 처리할 수 있습니다.
이러한 기법은 다양한 알고리즘 문제에서 유용하므로 꼭 숙지해두시기 바랍니다.

추가 연습 문제

  • 1. 예제의 배열 A를 바꿔가며 구간 합을 구해보시오.
  • 2. 다른 알고리즘 (세그먼트 트리 또는 펜윅 트리)을 이용하여 구간 합을 구하는 방법을 연구해보시오.
  • 3. 배열의 특정 인덱스의 값을 갱신하고 전체 구간 합을 다시 계산하는 문제를 연습해보시오.

참고 문헌

– 클리츠 알고리즘 문제집

– 온라인 코딩 테스트 관련 자료

– LeetCode, HackerRank의 구간 합 문제

파이썬 코딩테스트 강좌, 구간 합 구하기 2

안녕하세요! 파이썬 코딩 테스트 강좌에 오신 것을 환영합니다. 이번 강좌에서는
“구간 합 구하기 2” 문제를 다룰 것입니다. 알고리즘 문제를 해결하는 데 있어
구간 합을 효율적으로 계산하는 방법은 매우 중요합니다.
아래에서 문제 설명과 해결 과정을 단계별로 살펴보겠습니다.

문제 설명

주어진 N개의 정수 A[1], A[2], …, A[N]이 주어졌을 때,
Q개의 질의가 주어집니다. 각 질의는 두 정수 L과 R로 구성되며,
A[L]부터 A[R]까지의 합을 구하는 것입니다.
문제는 다음과 같습니다:

입력 형식:
첫 번째 줄에 정수 N(1 ≤ N ≤ 100,000)과 Q(1 ≤ Q ≤ 100,000)가 주어진다.
두 번째 줄에 N개의 정수를 공백으로 구분하여 입력받는다. |A[i]| ≤ 1,000,000
Q개의 질의는 다음과 같이 주어진다: 각 질의는 두 정수 L과 R (1 ≤ L ≤ R ≤ N)
로 구성된다.

출력 형식:
각 질의에 대한 A[L]부터 A[R]까지의 합을 출력한다.

문제를 효율적으로 푸는 방법

이러한 문제를 해결하기 위해서는 매 질의마다 구간의 합을 직접 계산하는 것이
아니라, 누적 합 (Prefix Sum)을 사용하는 것이 효율적입니다.
누적 합은 기본적으로 특정 구간의 합을 상수 시간 O(1) 안에 구할 수 있게 해줍니다.

누적 합 (Prefix Sum) 계산하기

누적 합을 구하는 방법은 다음과 같습니다:

  • 누적 합 배열 S를 생성합니다. 여기서 S[i]는 A[1]부터 A[i]까지의 합을 의미합니다.
  • S[0] = 0으로 초기화합니다. (편의상 0을 두어서 S[i]에서 S[L-1]을 빼는 방식으로 계산합니다.)
  • 그 다음 S[i]를 다음과 같이 계산합니다: S[i] = S[i-1] + A[i]

이를 통해 S[R] – S[L-1]로 한 번의 뺄셈 연산으로 구간 합을 구할 수 있습니다.

문제 풀이 코드

        
def calculate_prefix_sum(arr):
    n = len(arr)
    prefix_sum = [0] * (n + 1)
    for i in range(1, n + 1):
        prefix_sum[i] = prefix_sum[i - 1] + arr[i - 1]
    return prefix_sum

def range_sum(prefix_sum, L, R):
    return prefix_sum[R] - prefix_sum[L - 1]

N, Q = map(int, input().split())
A = list(map(int, input().split()))
prefix_sum = calculate_prefix_sum(A)

for _ in range(Q):
    L, R = map(int, input().split())
    print(range_sum(prefix_sum, L, R))
        
        

위의 코드는 다음과 같은 과정을 수행합니다:

  • 먼저, 주어진 배열 A의 길이 N에 대한 누적 합 배열을 계산하는 함수를 호출합니다.
  • 각 질의에 대해 L과 R을 입력받고, 해당 구간의 합을 출력합니다.

시간 복잡도 분석

이 문제의 시간 복잡도를 분석해보면 다음과 같습니다:

  • 누적 합 배열을 계산하는 데 O(N)의 시간이 소요됩니다.
  • 각 질의에 대한 구간 합을 계산하는 데 O(1)의 시간이 소요됩니다.
  • 따라서 전체 시간 복잡도는 O(N + Q)가 됩니다.

결론

구간 합 문제는 코딩 테스트에서 자주 출제되는 문제 중 하나입니다.
누적 합을 활용하면 문제를 효율적으로 해결할 수 있는 좋은 방법입니다.
이번 강좌에서 다룬 내용을 바탕으로 다양한 변형 문제들을 풀어보는 것도 좋습니다.
추가 질문이나 다른 알고리즘 문제에 대해 더 알고 싶다면 언제든지 댓글을 남겨주세요!