스위프트 코딩테스트 강좌, 수 정렬하기 1

이 글에서는 스위프트를 사용하여 알고리즘 문제를 해결하는 과정을 설명하고, 주어진 문제를 어떻게 접근하고 해결하는지에 대한 자세한 내용을 다룰 것입니다. 문제의 주제는 ‘수 정렬하기 1’입니다. 이 문제는 기본적인 정렬 알고리즘을 이해하고, 스위프트의 기본적인 문법을 사용하는 데 도움이 될 것입니다.

문제 설명

주어진 입력 수를 오름차순으로 정렬하시오.

입력

첫째 줄에 수의 개수 N (1 ≤ N ≤ 1,000,000)이 주어진다.
둘째 줄부터 N개의 줄에 걸쳐 수가 주어진다. 수는 절대값이 1,000,000보다 작거나 같은 정수이다.

출력

오름차순으로 정렬된 수를 한 줄에 하나씩 출력한다.

접근 방법

이 문제를 해결하기 위해서는 정렬 알고리즘이 필요합니다. 사용자가 입력한 수를 정렬하기 위해 다음 단계를 따릅니다:

  1. 입력 데이터를 읽어온다.
  2. 정렬 알고리즘을 사용하여 데이터를 정렬한다.
  3. 정렬된 데이터를 출력한다.

스위프트에서는 내장된 정렬 메서드를 사용할 수 있습니다. 그러나 정렬 알고리즘을 직접 구현하는 것도 좋은 연습이 될 것입니다. 여기서는 퀵 정렬(Quick Sort) 알고리즘을 사용하여 문제를 해결해보겠습니다.

스위프트 코드 구현

import Foundation

// 간단한 퀵 정렬 알고리즘 구현
func quickSort(_ array: [Int]) -> [Int] {
    guard array.count > 1 else { return array }
    
    let pivot = array[array.count / 2]
    let less = array.filter { $0 < pivot }
    let equal = array.filter { $0 == pivot }
    let greater = array.filter { $0 > pivot }
    
    return quickSort(less) + equal + quickSort(greater)
}

// 입력 받기
let n = Int(readLine()!)!
var numbers: [Int] = []

for _ in 0..

코드 설명

위의 코드 구현을 살펴보면 다음과 같은 단계로 되어있습니다:

  1. quickSort 함수는 입력 배열을 매개변수로 받아서 정렬된 배열을 반환합니다. 이 함수는 배열의 길이에 따라 분기합니다.
  2. 배열의 피벗(pivot)을 선택한 후, 피벗을 기준으로 세 개의 배열(less, equal, greater)로 나누어 집니다.
  3. 각각의 부분 배열에 대해 재귀적으로 quickSort를 호출하여 정렬합니다.
  4. 재조합하여 최종적으로 정렬된 배열을 반환합니다.

메인 부분에서는 사용자가 입력한 수의 개수와 수를 읽어오고, 이를 배열에 저장한 후, 정렬 함수를 호출하여 정렬된 결과를 출력합니다.

시간 복잡도 분석

퀵 정렬의 평균 시간 복잡도는 O(N log N)입니다. 그러나 최악의 경우(이미 정렬되어 있거나 모든 요소가 같은 경우)의 시간 복잡도는 O(N2)입니다. 그러나 이는 피벗 선택 방법에 따라서도 달라질 수 있으며, 특히 리니어 타임 성능을 보장하기 위해서는 랜덤 피벗 선택 전략을 사용할 수 있습니다.

결론

이 글에서는 스위프트를 사용하여 ‘수 정렬하기 1’ 문제를 해결하는 방법에 대해 다뤘습니다. 퀵 정렬 알고리즘을 통해 입력된 숫자를 정렬하는 과정을 통해 알고리즘의 기본 원리를 이해할 수 있었습니다. 다양한 정렬 알고리즘을 구현해 보는 것은 프로그래밍 실력을 향상시키는 데 큰 도움이 됩니다.

이러한 문제를 자주 풀어보며, 스위프트 언어에 대한 경험을 쌓는 것이 코딩 테스트에서 좋은 결과를 내는 데 큰 도움이 될 것입니다. 다음에는 다른 정렬 알고리즘이나 자료 구조에 대해 다뤄보도록 하겠습니다. 끝까지 읽어주셔서 감사합니다!

스위프트 코딩테스트 강좌, 소수 구하기

작성자: 조광형 | 날짜: [작성일자]

서론

프로그래밍 언어 스위프트(Swift)는 macOS 및 iOS 애플리케이션 개발에 널리 사용됩니다.
취업을 위한 알고리즘 시험에서 소수(prime number)를 찾는 문제는 자주 출제되며, 그 해결 방법에 대한 충분한 이해와 실습이 필요합니다.
이 글에서는 소수를 판별하는 알고리즘 문제를 예시로 들고, 그 해결 과정을 단계별로 설명하겠습니다.

문제 설명

문제: 주어진 정수 N 이하의 모든 소수를 구하라.

소수가 무엇인지에 대한 간단한 정의: 소수는 1과 자기 자신 외에는 약수가 없는 자연수입니다. 즉, 1과 N으로만 나누어 떨어지는 수입니다.
예를 들어, 2, 3, 5, 7, 11, 13, 17, 19 등이 소수입니다.
이 문제의 목표는 입력으로 주어진 N 이하의 모든 소수를 찾아 배열 또는 리스트 형태로 반환하는 것입니다.

구현 방안

소수를 찾는 문제는 여러 가지 접근 방법이 있지만, 여기서는 에라토스테네스의 체(Sieve of Eratosthenes) 알고리즘을 사용하여 소수를 찾는 방법을 다루겠습니다.
이 방법은 O(N log log N)의 시간 복잡도로 소수를 효율적으로 찾을 수 있습니다.

1단계: 배열 초기화

먼저, N+1 크기의 부울 배열을 생성하여 각 인덱스가 소수인지 여부를 나타내도록 초기화합니다.
모든 인덱스는 true로 초기화하며, 인덱스 0과 1은 false로 설정합니다.

2단계: 소수 판별

2부터 시작하여 각 숫자를 검사합니다.
현재 숫자가 소수로 판별되면, 그 숫자의 배수를 모두 false로 설정합니다.
이 과정을 N의 제곱근까지 반복합니다.

3단계: 소수 출력

최종적으로 true로 남아 있는 인덱스는 모두 소수입니다.
이 인덱스를 이용해 결과 리스트를 출력합니다.

스위프트 코드 구현

        
        func sieveOfEratosthenes(n: Int) -> [Int] {
            // N+1 크기의 배열 초기화
            var isPrime = [Bool](repeating: true, count: n + 1)
            isPrime[0] = false // 0은 소수가 아님
            isPrime[1] = false // 1은 소수가 아님

            // 소수를 판별
            for i in 2...Int(sqrt(Double(n))) {
                if isPrime[i] {
                    for multiple in stride(from: i * i, through: n, by: i) {
                        isPrime[multiple] = false
                    }
                }
            }

            // 소수 리스트 생성
            var primes: [Int] = []
            for i in 2...n {
                if isPrime[i] {
                    primes.append(i)
                }
            }
            
            return primes
        }

        // 예시 실행
        let n = 30
        let primesUnderN = sieveOfEratosthenes(n: n)
        print("소수:", primesUnderN)
        
        

코드 설명

위의 스위프트 코드는 주어진 N 이하의 소수를 찾는 방법을 구현합니다.
func sieveOfEratosthenes라는 함수는 정수 N을 입력받아 따르는 과정을 실행합니다.

  1. 배열 초기화: N+1 크기의 부울 배열을 생성하여 모든 값을 true로 설정합니다.
  2. 소수 판별: 2부터 시작하여 모든 소수를 판별하고, 해당 소수의 배수를 false로 설정합니다.
  3. 소수 출력: 최종 배열을 확인하여 true로 남아 있는 모든 인덱스를 리스트 형태로 반환합니다.

예제 실행

N = 30일 때, 위의 코드를 실행하면 다음과 같은 결과가 출력됩니다:

        
        소수: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
        
        

결론

소수를 계산하는 것은 프로그래밍을 배우는 데 있어 중요한 주제가 될 수 있으며, 면접에서도 흔히 출제됩니다.
에라토스테네스의 체 알고리즘을 사용하면 효율적으로 소수를 찾을 수 있습니다.
이 글에서 설명한 방법과 코드를 참고하여 다양한 입력값에 대해 직접 테스트해보시기 바랍니다.
소수를 찾는 것은 알고리즘을 연습하는 좋은 방법이며, 더 복잡한 문제를 해결하기 위한 기초가 될 수 있습니다.

이 글이 도움이 되셨다면 댓글을 남겨주세요!

스위프트 코딩테스트 강좌, 세일즈맨의 고민

문제 정의

‘세일즈맨의 고민’ 문제는 주어진 도시들 사이의 거리 정보를 바탕으로, 세일즈맨이 모든 도시를
한 번씩 방문하고, 다시 출발 도시로 돌아오는 최소 경로를 찾는 문제입니다. 이는 최적화 문제로,
그래프 이론의 한 가지 형태인 외판원 문제(TSP, Traveling Salesman Problem)으로
알려져 있습니다. 이 문제는 NP-완전 문제로 알려져 있으며, 해결하기 위한 다양한 방법이 존재합니다.

문제 설명

다음과 같은 조건이 주어집니다:

  • n개의 도시가 있음.
  • 각 도시는 1에서 n까지의 정수로 표현됨.
  • 도시 간의 거리는 유향 그래프 형태로 주어지며, 거리 정보는 이차원 배열로 표현됨.
  • 세일즈맨은 모든 도시를 한 번씩 방문하고, 출발 도시로 돌아와야 함.

입력 포맷

첫 번째 줄에는 도시의 수인 n이 주어집니다. 그 다음 n개의 줄에는 각 도시 간의 거리 행렬이 주어집니다.
거리 행렬은 다음과 같이 구성됩니다:

        0 10 15 20
        10 0 35 25
        15 35 0 30
        20 25 30 0
        

위의 예시에서 첫 번째 줄은 4개의 도시가 있으며, 각 도시 간의 거리를 나타냅니다.
예를 들어, 도시 1과 도시 2 사이의 거리는 10, 도시 1과 도시 3 사이의 거리는 15임을 알 수 있습니다.

출력 포맷

최소 경로의 총 거리를 출력합니다.

문제 해결 접근법

이 문제는 다양한 방법으로 접근할 수 있지만, 여기서는 백트래킹동적 계획법(DP)
이용한 방법을 설명하겠습니다. 백트래킹을 사용하여 모든 경로를 탐색하면서 최소 경로를
찾을 수 있지만, 도시 수가 많아질수록 계산량이 폭발적으로 증가하므로, 동적 계획법을 통한
메모이제이션을 함께 사용하면 효율성을 높일 수 있습니다.

알고리즘 구현

우선 순열을 이용한 백트래킹 기법을 통해 모든 경로를 생성한 후, 경로의 거리를 계산하여
최소값을 업데이트하는 방식으로 구현할 수 있습니다. 아래는 이 알고리즘을 스위프트로 구현한
예제 코드입니다.

        func tsp(graph: [[Int]], visited: inout [Bool], currentIndex: Int, count: Int, cost: Int, ans: inout Int) {
            // 모든 도시를 방문한 경우
            if count == graph.count && graph[currentIndex][0] > 0 {
                ans = min(ans, cost + graph[currentIndex][0])
                return
            }
            for i in 0.. 0 {
                    visited[i] = true
                    tsp(graph: graph, visited: &visited, currentIndex: i, count: count + 1, cost: cost + graph[currentIndex][i], ans: &ans)
                    visited[i] = false
                }
            }
        }

        func findMinCost(graph: [[Int]]) -> Int {
            var visited = [Bool](repeating: false, count: graph.count)
            var ans = Int.max
            visited[0] = true
            tsp(graph: graph, visited: &visited, currentIndex: 0, count: 1, cost: 0, ans: &ans)
            return ans
        }

        let graph = [
            [0, 10, 15, 20],
            [10, 0, 35, 25],
            [15, 35, 0, 30],
            [20, 25, 30, 0]
        ]

        let result = findMinCost(graph: graph)
        print("최소 경로의 거리: \(result)")
        

코드 설명

위 코드는 다음과 같은 구조로 되어 있습니다:

  • tsp 함수: 재귀적으로 도시를 방문하는 모든 경로를 탐색하며,
    현재 도시에서 방문하지 않은 모든 도시를 순회합니다. 방문한 도시의 비용이 최소일 경우
    현재 경로의 비용을 최소값으로 업데이트합니다.
  • findMinCost 함수: 초기화 기능을 하며, 전체 경로를 탐색하기 위해
    첫 번째 도시(0)를 방문한 상태로 tsp 함수를 호출합니다.

복잡도 분석

이 알고리즘의 시간 복잡도는 O(n!)입니다. 이는 각 도시를 순회하고 모든 경로를 탐구해야 하기
때문입니다. n이 작을 경우에는 사용할 수 있지만, n이 커질 경우 비효율적입니다.
따라서 보다 효율적인 방법이 필요한 경우 동적 계획법을 적용하여 비트마스크를 사용하는
방식으로 복잡도를 줄일 수 있습니다. 이 방식은 O(n^2 * 2^n)의 시간 복잡도를 가지며,
n이 20 이하일 경우 실용적입니다.

결론

‘세일즈맨의 고민’ 문제는 현실의 다양한 최적화 문제와 연관이 깊으며, 효과적인 알고리즘 설계
과정을 통해 문제를 해결하는 데 중요한 통찰력을 제공합니다. 코딩 테스트 준비 시,
이와 같은 문제를 풀어봄으로써 그래프 알고리즘 및 동적 계획법에 대한 이해도를 높이고,
체계적인 문제 해결 능력을 기를 수 있습니다.

스위프트 코딩테스트 강좌, 소수 & 팰린드롬 수 중에서 최솟값 찾기

안녕하세요! 이번 강좌에서는 소수(prime number)와 팰린드롬 수(palindrome number)의 중에서 최솟값을 찾는 알고리즘 문제를 살펴보도록 하겠습니다. 소수와 팰린드롬 수는 기본적인 수학 개념이지만, 이 둘을 결합하여 특정한 요구사항을 해결하는 문제는 코딩테스트에서 자주 등장합니다. 따라서 이 문제를 통해 효율적인 알고리즘 설계 및 구현 능력을 키워보세요.

문제 설명

주어진 범위 내의 모든 정수 중에서 소수이면서 팰린드롬 수인 수들의 최솟값을 찾는 함수를 작성하세요.

예를 들어, 1부터 100까지의 범위에서 소수이면서 팰린드롬 수인 숫자를 나열하면, 그 중에서 최솟값은 2입니다.

입력

정수 n (2 <= n <= 10,000)이 주어집니다. 이 범위 내에서 소수이면서 팰린드롬 수를 찾아야 합니다.

출력

소수이면서 팰린드롬 수들의 최솟값을 출력합니다. 만약 해당 조건을 만족하는 수가 없다면 “조건을 만족하는 수가 없습니다.”라는 메시지를 출력합니다.

문제 해결 과정

문제를 해결하기 위해서는 다음 단계로 나누어 해결할 수 있습니다:

  1. 소수를 판단하는 함수 작성하기
  2. 팰린드롬 수를 판단하는 함수 작성하기
  3. 입력된 범위 내에서 소수이면서 팰린드롬 수를 찾기
  4. 최솟값을 반환하기

1. 소수를 판단하는 함수 작성하기

소수는 1과 자기 자신만 약수로 가지는 수입니다. 이를 판단하기 위해, 2부터 sqrt(n)까지 숫자로 나누어지는지를 체크하여 소수 여부를 판단할 수 있습니다.

func isPrime(_ number: Int) -> Bool {
        guard number > 1 else { return false }
        for i in 2...Int(sqrt(Double(number))) {
            if number % i == 0 {
                return false
            }
        }
        return true
    }

2. 팰린드롬 수를 판단하는 함수 작성하기

팰린드롬 수는 앞으로 읽어도 뒤로 읽어도 같은 수입니다. 이를 체크하기 위해서는 수를 문자열로 변환한 후, 해당 문자열이 뒤집힌 것과 같은지를 비교하면 됩니다.

func isPalindrome(_ number: Int) -> Bool {
        let string = String(number)
        return string == String(string.reversed())
    }

3. 입력된 범위 내에서 소수이면서 팰린드롬 수 찾기

앞서 작성한 두 함수(isPrime, isPalindrome)를 활용하여 2부터 n까지의 모든 정수에서 이 두 조건을 만족하는 수를 확인합니다.

func findMinPrimePalindrome(upTo n: Int) -> Int? {
        var minPrimePalindrome: Int? = nil

        for i in 2...n {
            if isPrime(i) && isPalindrome(i) {
                if minPrimePalindrome == nil || i < minPrimePalindrome! {
                    minPrimePalindrome = i
                }
            }
        }
        return minPrimePalindrome
    }

4. 최솟값 반환하기

최솟값을 찾은 후 값을 반환합니다. 만약 최솟값이 없다면 적절한 메시지를 출력하도록 합니다.

let n = 100
if let minValue = findMinPrimePalindrome(upTo: n) {
    print("소수이면서 팰린드롬 수의 최솟값은: \(minValue)")
} else {
    print("조건을 만족하는 수가 없습니다.")
}

최종 코드

모든 부분을 통합하여 최종 코드를 작성하면 다음과 같습니다:

func isPrime(_ number: Int) -> Bool {
        guard number > 1 else { return false }
        for i in 2...Int(sqrt(Double(number))) {
            if number % i == 0 {
                return false
            }
        }
        return true
    }

    func isPalindrome(_ number: Int) -> Bool {
        let string = String(number)
        return string == String(string.reversed())
    }

    func findMinPrimePalindrome(upTo n: Int) -> Int? {
        var minPrimePalindrome: Int? = nil
        
        for i in 2...n {
            if isPrime(i) && isPalindrome(i) {
                if minPrimePalindrome == nil || i < minPrimePalindrome! {
                    minPrimePalindrome = i
                }
            }
        }
        return minPrimePalindrome
    }

    let n = 100
    if let minValue = findMinPrimePalindrome(upTo: n) {
        print("소수이면서 팰린드롬 수의 최솟값은: \(minValue)")
    } else {
        print("조건을 만족하는 수가 없습니다.")
    }

결론

이번 강좌에서는 스위프트 언어를 사용하여 소수이면서 팰린드롬 수를 찾는 문제를 다뤄보았습니다. 이 문제를 통해 기본적인 알고리즘 설계 및 구현 능력을 익힐 수 있었기를 바랍니다. 또한, 문제를 해결하기 위해서 여러 가지 기능을 모두 조합하여 사용하는 방법을 배웠습니다. 다음 강좌에서도 더욱 흥미롭고 도전적인 문제를 만나길 기대합니다!

감사합니다!

스위프트 코딩테스트 강좌, 세그먼트 트리

안녕하세요! 이번 강좌에서는 데이터 구조 중 하나인 세그먼트 트리에 대해 자세히 살펴보도록 하겠습니다. 세그먼트 트리는 주로 구간 쿼리를 효율적으로 처리할 수 있는 자료구조로, 특히 배열의 구간 합이나 구간 최솟값, 구간 최댓값 등을 구할 때 유용합니다. 이 글에서는 세그먼트 트리에 대한 기본 개념과 구현 방법, 그리고 실전에서 자주 출제되는 문제를 함께 해결해보겠습니다.

1. 세그먼트 트리란?

세그먼트 트리는 배열의 구간 정보를 효율적으로 관리하는데 강력한 도구입니다. 보통 배열의 크기가 N일 때, 세그먼트 트리는 대략 2 * 2⌈log₂(N)⌉의 메모리 공간을 사용합니다. 이는 포화 이진트리 구조를 활용하기 때문입니다. 기본적으로 세그먼트 트리는 다음 두 가지 작업을 효율적으로 수행할 수 있습니다.

  • 구간 쿼리: 특정 구간의 정보를 빠르게 가져올 수 있습니다.
  • 업데이트: 배열의 특정 요소를 변경한 후, 이로 인해 영향을 받는 구간 정보를 빠르게 갱신할 수 있습니다.

2. 세그먼트 트리의 구조

세그먼트 트리는 노드로 구성되며, 각 노드는 특정 구간을 나타냅니다. 예를 들어, 배열의 인덱스 0부터 N-1까지의 구간을 관리하는 루트 노드가 존재하고, 이 노드는 두 개의 자식 노드를 통해 배열을 절반으로 나누어 관리합니다. 이런 방식으로 배열을 계속 나누면서 각각의 노드가 특정 구간의 정보를 갖게 됩니다.

2.1 노드 정의

각 노드는 다음과 같은 정보를 가집니다:

  • 시작 인덱스 (start): 해당 구간의 시작 지점
  • 끝 인덱스 (end): 해당 구간의 끝 지점
  • 값(value): 해당 구간의 정보를 저장할 변수 (예: 합, 최솟값 등)

3. 세그먼트 트리 생성 및 쿼리

세그먼트 트리를 구현하기 위해서는 먼저 트리를 구성해야 합니다. 이를 위해, 배열을 입력받아 세그먼트 트리 노드를 재귀적으로 생성하는 방법을 사용합니다. 간단한 예로, 구간 합 세그먼트 트리를 만들어보겠습니다.


// Swift Code
class SegmentTree {
    var tree: [Int] // 세그먼트 트리를 저장할 배열
    var n: Int // 배열 크기

    init(_ data: [Int]) {
        self.n = data.count
        self.tree = Array(repeating: 0, count: 4 * n) // 트리 배열 초기화
        buildTree(data: data, node: 1, start: 0, end: n - 1)
    }

    // 배열의 구간을 사용하여 세그먼트 트리 구성
    func buildTree(data: [Int], node: Int, start: Int, end: Int) {
        if start == end {
            tree[node] = data[start] // 리프 노드에 값 저장
        } else {
            let mid = (start + end) / 2
            buildTree(data: data, node: 2 * node, start: start, end: mid) // 왼쪽 서브트리
            buildTree(data: data, node: 2 * node + 1, start: mid + 1, end: end) // 오른쪽 서브트리
            tree[node] = tree[2 * node] + tree[2 * node + 1] // 부모 노드 값 갱신
        }
    }
}

4. 세그먼트 트리 쿼리 처리하기

세그먼트 트리는 이제 구간 합을 계산하는 기능을 추가해야 합니다. 구간 합 쿼리를 처리하기 위해 다음과 같은 함수를 추가하겠습니다:


// 주어진 구간의 합을 구하는 함수
func query(node: Int, start: Int, end: Int, l: Int, r: Int) -> Int {
    if r < start || end < l { // 구간이 겹치지 않는 경우
        return 0 // 기본값
    }
    if l <= start && end <= r { // 구간이 완전히 포함되는 경우
        return tree[node]
    }
    let mid = (start + end) / 2
    let leftSum = query(node: 2 * node, start: start, end: mid, l: l, r: r) // 왼쪽 서브트리 쿼리
    let rightSum = query(node: 2 * node + 1, start: mid + 1, end: end, l: l, r: r) // 오른쪽 서브트리 쿼리
    return leftSum + rightSum // 결과 합산
}

5. 세그먼트 트리 업데이트하기

배열의 원소를 업데이트할 수 있는 함수도 추가합니다. 배열의 특정 인덱스를 변경했을 때, 세그먼트 트리의 정보를 신속하게 갱신하는 방법은 다음과 같습니다:


// 배열의 특정 인덱스를 업데이트 하는 함수
func update(node: Int, start: Int, end: Int, idx: Int, value: Int) {
    if start == end { // 리프 노드 도착
        tree[node] = value // 해당 노드를 업데이트
    } else {
        let mid = (start + end) / 2
        if start <= idx && idx <= mid {
            update(node: 2 * node, start: start, end: mid, idx: idx, value: value) // 왼쪽 서브트리 업데이트
        } else {
            update(node: 2 * node + 1, start: mid + 1, end: end, idx: idx, value: value) // 오른쪽 서브트리 업데이트
        }
        tree[node] = tree[2 * node] + tree[2 * node + 1] // 부모 노드 값 갱신
    }
}

6. 실전 문제 예제

이제 세그먼트 트리의 기본 구조와 쿼리, 업데이트 방법을 살펴보았으니, 실전에서 자주 출제되는 문제를 하나 다뤄보겠습니다. 문제는 다음과 같습니다:

문제 설명

배열이 주어질 때, 다음 질문에 답하시오:

  1. 구간 [L, R]의 합을 구하라.
  2. 인덱스 I의 값을 V로 업데이트하라.

입력 형식

N (배열 크기)
arr[0], arr[1], ..., arr[N-1]
Q (질문 개수)
각 질문은 다음과 같은 형식으로 주어진다:
1 L R (구간 합 쿼리)
2 I V (업데이트 쿼리)

출력 형식

각 구간 합 쿼리에 대해 출력

예제

5
1 2 3 4 5
3
1 1 3
2 2 10
1 1 3
예제 출력
6

7. 문제 해결 과정

  1. 입력 받은 배열에 대해 세그먼트 트리를 구축합니다.
  2. 쿼리 타입에 따라, 구간 쿼리일 경우에는 query() 함수를 호출하고, 업데이트 쿼리일 경우에는 update() 함수를 호출합니다.
  3. 결과를 출력합니다.

// 문제를 해결하는 메인 함수
import Foundation

func main() {
    // 입력 처리
    let n = Int(readLine()!)!
    let arr = readLine()!.split(separator: " ").map { Int($0)! }
    let q = Int(readLine()!)!

    // 세그먼트 트리 구축
    let segmentTree = SegmentTree(arr)

    // 쿼리 처리
    for _ in 0..

8. 마무리

이번 세그먼트 트리 강좌를 통해 데이터 구조의 중요성과 그 활용 방법을 배웠습니다. 세그먼트 트리는 다양한 구간 쿼리 문제에 효과적으로 사용할 수 있습니다. 더 많은 연습 문제를 통해 세그먼트 트리의 적용 능력을 키우시길 바랍니다. 감사합니다!