C++ 코딩테스트 강좌, 위상 정렬

안녕하세요! 이번 글에서는 위상 정렬에 대해 알아보겠습니다. 위상 정렬은 방향성 비순환 그래프(DAG, Directed Acyclic Graph)에서 정점을 선형으로 나열하는 알고리즘으로, 특정한 순서를 유지해야 할 때 유용합니다. 예를 들어 작업의 종속성을 처리하거나 컴파일러가 코드의 실행 순서를 결정할 때 사용됩니다.

문제 설명

다음 문제를 해결해 보겠습니다.

문제: 작업 스케줄링

여러 개의 작업이 주어졌을 때, 각 작업은 특정한 선행 작업이 필요합니다. 선행 작업이 모두 완료된 후에만 해당 작업을 수행할 수 있습니다. 그래프의 정점은 작업을 나타내고, 간선은 선행 작업을 나타냅니다. 주어진 작업을 가능한 순서로 나열하시오.

입력

첫 번째 줄에는 정점의 개수 N (1 ≤ N ≤ 1000)과 간선의 개수 M (0 ≤ M ≤ 10000)이 주어진다.

다음 M개의 줄에는 x y 쌍이 주어지며, 이는 작업 x가 작업 y보다 먼저 수행되어야 함을 의미한다.

출력

작업을 수행할 수 있는 순서를 한 줄에 공백으로 구분하여 출력한다. 만약 순서가 불가능하다면 -1을 출력한다.

예제 입력

    6 6
    1 2
    1 3
    2 4
    3 4
    4 5
    5 6
    

예제 출력

1 2 3 4 5 6

위상 정렬의 원리

위상 정렬은 두 가지 방법으로 구현할 수 있습니다: DFS(깊이 우선 탐색)BFS(너비 우선 탐색). 여기서는 BFS를 이용한 Kahn의 알고리즘을 소개합니다. Kahn의 알고리즘은 다음과 같은 절차로 진행됩니다.

  1. 모든 정점의 진입 차수를 기록합니다.
  2. 진입 차수가 0인 정점을 큐에 넣습니다.
  3. 큐에서 정점을 하나씩 꺼내고, 그 정점을 결과 리스트에 추가합니다.
  4. 꺼낸 정점으로부터 나가는 모든 간선을 제거하고, 각 간선의 도착 정점의 진입 차수를 업데이트합니다. 진입 차수가 0이 되는 정점을 큐에 추가합니다.
  5. 큐가 빌 때까지 반복합니다. 결과 리스트의 크기가 입력한 정점의 개수와 다르면 사이클이 존재하는 것이므로 -1을 반환합니다.

기본 코드 구현

아래는 C++로 위상 정렬을 구현한 기본적인 코드입니다.


#include <iostream>
#include <vector>
#include <queue>
using namespace std;

void topologicalSort(int n, vector<vector<int>> &graph) {
    vector<int> inDegree(n + 1, 0);
    vector<int> result;

    // 진입 차수 계산
    for (int i = 1; i <= n; i++) {
        for (int j : graph[i]) {
            inDegree[j]++;
        }
    }

    queue<int> q;

    // 진입 차수가 0인 정점 큐에 삽입
    for (int i = 1; i <= n; i++) {
        if (inDegree[i] == 0) {
            q.push(i);
        }
    }

    while (!q.empty()) {
        int u = q.front();
        q.pop();
        result.push_back(u);

        for (int v : graph[u]) {
            inDegree[v]--;
            if (inDegree[v] == 0) {
                q.push(v);
            }
        }
    }

    // 사이클 확인
    if (result.size() != n) {
        cout << -1 << endl;
    } else {
        for (int i = 0; i < result.size(); i++) {
            cout << result[i] << ' ';
        }
        cout << endl;
    }
}

int main() {
    int n, m;
    cin >> n >> m;
    vector<vector<int>> graph(n + 1);

    for (int i = 0; i < m; i++) {
        int x, y;
        cin >> x >> y;
        graph[x].push_back(y);
    }

    topologicalSort(n, graph);
    return 0;
}
    

코드 설명

위 코드에서는 먼저 진입 차수를 담기 위해 inDegree라는 배열을 선언합니다. 각 정점의 진입 차수를 계산한 뒤, 진입 차수가 0인 정점을 큐에 넣습니다. 그 다음 큐에서 정점을 꺼내고, 꺼낸 정점으로부터 나가는 간선을 모두 제거하고 진입 차수를 업데이트합니다. 만약 result 리스트의 크기가 정점의 개수와 다르면 사이클이 존재하므로 -1을 출력합니다.

복잡도 분석

위상 정렬의 시간 복잡도는 O(N + M)입니다. 여기서 N은 정점의 개수, M은 간선의 개수입니다. 진입 차수를 세는데 O(M) 시간이 소요되고, 각 정점마다 진입 차수를 업데이트하는 과정에서도 O(M) 시간이 걸립니다. 따라서 전체적으로 O(N + M)의 시간 복잡도를 가집니다. 공간 복잡도는 O(N + M)으로, 그래프를 저장하기 위한 리스트와 진입 차수 배열을 고려해야 합니다.

추가 연습 문제

아래의 추가 연습 문제를 통해 위상 정렬을 더 깊이 이해하고 적용해보세요.

  1. 주어진 작업을 기반으로 다양한 작업 조합을 만들고 위상 정렬을 적용해 보세요.
  2. 사이클이 포함된 그래프를 입력으로 주어졌을 때, 적절한 에러 처리를 구현해 보세요.
  3. 진입 차수가 같은 정점이 여러 개일 경우, 그 중 하나의 정점을 무작위로 선택하도록 구현해 보세요.

결론

이번 포스트에서는 위상 정렬의 개념과 구현 방법, 예제 문제를 통해 위상 정렬의 활용 방법에 대해 배워보았습니다. 위상 정렬은 다양한 분야에서 많이 응용되는 알고리즘이므로 충분히 이해하고 연습하는 것이 중요합니다.

이제 여러분도 위상 정렬을 활용하여 복잡한 작업을 정렬하고 관리하는 데에 자신감을 가질 수 있기를 바랍니다. 계속해서 연습하고 다양한 문제를 풀어보세요!

C++ 코딩테스트 강좌, 원하는 정수 찾기

안녕하세요! 여러분과 함께하는 C++ 코딩 테스트 강좌입니다. 오늘의 주제는 ‘원하는 정수 찾기’입니다. 이 강좌는 C++로 코딩 테스트를 준비하는 여러분에게 도움이 될 것입니다. 문제를 이해하고 올바른 해결 방법을 찾는 과정을 자세히 설명하겠습니다. 본 강좌는 총 20,000자 이상으로 설계되어 있습니다.


문제 설명

주어진 정수 배열 arr와 하나의 정수 target이 있습니다. arr에서 target을 찾아 그 인덱스를 반환하는 프로그램을 작성하세요. arrtarget이 존재하지 않을 경우 -1을 반환합니다. 배열의 길이는 최대 10^6입니다. 배열은 정렬되어 있지 않을 수도 있습니다.

입력

arr = [2, 3, 4, 7, 11, 15, 20]
target = 7

출력

결과: 3

문제 분석

이 문제는 배열에서 특정 값을 찾는 문제로, 다양한 방식으로 해결할 수 있습니다. 일반적인 방식으로는 선형 탐색과 이진 탐색이 있습니다. 하지만 배열이 정렬되어 있는 경우에는 이진 탐색이 더 효율적입니다. 하지만 주어진 문제에서는 배열이 정렬되어 있지 않아 선형 탐색을 사용해 문제를 해결하겠습니다.

알고리즘 선택

문제에서 정렬되지 않은 배열을 주기 때문에 선형 탐색(linear search)을 사용할 것입니다. 선형 탐색은 배열의 각 요소를 하나씩 확인하여 찾고자 하는 값을 찾는 단순한 알고리즘입니다. 시간 복잡도는 O(n)입니다.

선형 탐색 알고리즘

선형 탐색의 기본 아이디어는 다음과 같습니다:

  1. 배열의 첫 번째 요소부터 시작합니다.
  2. 원하는 정수를 찾을 때까지 배열의 각 요소를 순차적으로 비교합니다.
  3. 찾으면 해당 요소의 인덱스를 반환합니다.
  4. 배열 끝에 도달할 때까지 찾지 못하면 -1을 반환합니다.

코드 구현

이제 C++로 선형 탐색 알고리즘을 구현해 보겠습니다. 아래에 코드를 작성하였습니다:

#include <iostream>
#include <vector>

int findTarget(const std::vector<int> &arr, int target) {
    for (size_t i = 0; i < arr.size(); ++i) {
        if (arr[i] == target) {
            return i; // Target found, return index
        }
    }
    return -1; // Target not found
}

int main() {
    std::vector<int> arr = {2, 3, 4, 7, 11, 15, 20};
    int target = 7;

    int index = findTarget(arr, target);
    if (index != -1) {
        std::cout << "결과: " << index << std::endl;
    } else {
        std::cout << "결과: -1" << std::endl;
    }

    return 0;
}

코드 설명

위의 코드에서 findTarget 함수는 배열과 찾고자 하는 값을 입력으로 받아서 해당 값을 배열에서 찾아 반환합니다.

  1. for 루프를 통해 배열의 각 요소에 접근합니다.
  2. 현재 요소가 target과 같은지 확인합니다. 같다면 해당 인덱스를 반환합니다.
  3. 모든 요소를 확인한 후에도 찾지 못했다면 -1을 반환하여 ‘찾지 못했다’는 의미를 명시합니다.

성능 분석

위의 선형 탐색 알고리즘의 시간 복잡도는 O(n)입니다. 최악의 경우에는 배열의 모든 요소를 확인해야 하므로, n이 배열의 크기일 때 이런 성능을 보입니다. 메모리 복잡도는 O(1)입니다.

테스트

이제 몇 가지 테스트 케이스를 만들어 알고리즘의 유효성을 검증해 보겠습니다.

테스트 케이스

  1. arr = [1, 2, 3, 4, 5], target = 3 -> 결과: 2
  2. arr = [10, 20, 30, 40, 50], target = 25 -> 결과: -1
  3. arr = [5, 1, 9, 3], target = 1 -> 결과: 1

결론

오늘은 C++을 사용하여 원하는 정수를 찾는 문제를 해결했습니다. 우리는 선형 탐색 알고리즘을 사용하여 배열에서 특정 숫자를 찾는 방법을 배웠습니다. 이런 문제는 실제 인터뷰에서도 자주 출제되므로, 충분한 연습을 통해 능숙해져야 합니다. 다음 강좌에서는 다른 알고리즘과 더 복잡한 문제를 다룰 예정이니 많은 기대 바랍니다!

참고자료

자세한 내용은 다음 자료를 참조하시기 바랍니다:

C++ 코딩테스트 강좌, 오큰수 구하기

이번 강좌에서는 C++을 사용하여 “오큰수 구하기”라는 문제를 해결해보겠습니다. 이 문제는 주어진 수열에서 각 원소에 대해 자신보다 크고, 가장 가까운 위치에 있는 수를 찾는 문제입니다. 이를 통해 스택을 활용한 문제 해결 방법과 효율적인 알고리즘 설계를 배워보겠습니다.

문제 설명

주어진 정수 배열에서 각 배열의 원소에 대해, 그 원소보다 큰 수가 오른쪽에 있는 가장 가까운 위치를 찾아 해당 수를 출력합니다. 만약 그런 수가 존재하지 않는다면 -1을 출력해야 합니다.

입력

  • 첫 번째 줄에 배열의 크기 N (1 ≤ N ≤ 1,000,000)
  • 두 번째 줄에 N개의 정수로 이루어진 배열 A (0 ≤ A[i] ≤ 1,000,000)

출력

  • N개의 정수로 이루어진 배열 B를 출력해야 하며, B[i]는 A[i]의 오른쪽에서 가장 가까운 큰 수입니다. 그런 수가 없다면 -1을 출력해야 합니다.

예제 입력


5
2 1 2 4 3

예제 출력


4 2 4 -1 -1

문제 접근 방법

이 문제를 해결하는 가장 효율적인 방법은 스택(Stack) 자료구조를 사용하는 것입니다. 배열의 맨 뒤에서부터 시작하여 각 원소를 순회하면서 다음과 같은 과정을 수행합니다.

  1. 스택이 비어있지 않고, 현재 원소가 스택의 가장 위에 있는 원소보다 크면, 스택에서 원소를 pop 합니다. 이 때 pop한 원소는 현재 원소의 오큰수가 됩니다.
  2. 현재 원소의 인덱스와 오큰수 값을 배열에 저장합니다.
  3. 현재 원소를 스택에 push합니다.

이 과정을 배열의 처음까지 반복하여 모든 원소의 오큰수를 찾을 수 있습니다.

시간 복잡도

이 알고리즘의 시간 복잡도는 O(N)입니다. 각 원소는 스택에 단 한 번 push되고 단 한 번 pop되므로, 모든 원소를 들른다고 하더라도 스택의 원소 개수는 N을 넘지 않습니다.

구현

이제 실제로 위의 알고리즘을 C++로 구현해보겠습니다.


#include <iostream>
#include <vector>
#include <stack>
using namespace std;

void findNextGreaterElement(const vector<int>& arr, vector<int>& result) {
    stack<int> s; // 스택 선언

    for (int i = arr.size() - 1; i >= 0; --i) {
        // 스택에서 현재 원소보다 작거나 같은 원소를 제거
        while (!s.empty() && s.top() <= arr[i]) {
            s.pop();
        }
        // 스택이 비어있으면, 오큰수는 -1
        if (s.empty()) {
            result[i] = -1;
        } else {
            result[i] = s.top(); // 스택의 가장 위 원소가 오큰수
        }
        s.push(arr[i]); // 현재 원소를 스택에 추가
    }
}

int main() {
    int N;
    cout << "배열의 크기를 입력하세요: ";
    cin >> N;

    vector<int> arr(N);
    cout << "배열 원소를 입력하세요: ";
    for (int i = 0; i < N; ++i) {
        cin >> arr[i];
    }

    vector<int> result(N);
    findNextGreaterElement(arr, result);

    cout << "오큰수: ";
    for (int i = 0; i < N; ++i) {
        cout << result[i] << " ";
    }
    cout << endl;

    return 0;
}

코드 설명

위의 코드는 “오큰수 구하기” 문제를 해결하기 위한 C++ 프로그램입니다. 다음은 각 부분에 대한 설명입니다.

  • 헤더 파일 포함: iostream, vector, stack 라이브러리를 포함하여 입출력, 벡터 사용, 스택 사용을 가능하게 합니다.
  • findNextGreaterElement 함수: 이 함수는 입력으로 주어진 배열과 결과를 저장할 벡터를 받아, 오큰수를 찾는 핵심 로직을 포함하고 있습니다.
  • main 함수: 프로그램의 시작점으로, 사용자로부터 배열의 크기와 원소를 입력받고, 오큰수를 계산한 후 결과를 출력합니다.

결론

이번 강좌에서는 “오큰수 구하기” 문제를 C++을 사용하여 효율적으로 해결하는 방법을 배웠습니다. 스택을 활용하여 배열의 각 원소에 대해 오큰수를 찾아내는 과정에서 스택의 특징과 알고리즘의 효율성을 느낄 수 있었습니다. 실제 코딩 테스트에서는 이러한 자료구조와 알고리즘을 활용할 수 있는 능력이 중요합니다.

코딩테스트에서 자주 출제되는 문제인 만큼 다양한 변형 문제에 대해서도 고민해보고, 스택을 활용한 문제 해결 능력을 키우는 것이 중요합니다. 앞으로도 유사한 문제들을 접하면서, 다양한 알고리즘과 자료구조를 익혀보시기 바랍니다.

C++ 코딩테스트 강좌, 외판원의 순회 경로 짜기

작성자: 조광형

작성일: 2024년 11월 26일

문제 정의

“외판원 문제”는 주어진 도시들을 모두 방문하고 다시 시작점으로 돌아오는 최소 경로를 찾는 문제입니다.
이 문제는 컴퓨터 과학 및 최적화 이론에서 중요한 문제이며, 다양한 실제 문제에 응용될 수 있습니다.
외판원 문제는 특히 NP-완전 문제로 알려져 있으며, 효과적인 알고리즘을 통해 해결할 수 있는 방법을 탐구해 보겠습니다.

문제 설명

                주어진 N개의 도시가 있으며, 각 도시 사이의 거리가 주어집니다. 외판원은 
                모든 도시를 한 번씩 방문한 후, 다시 시작 도시로 돌아와야 합니다. 
                최소 비용으로 모든 도시를 방문할 경로를 구하세요.
                
                입력:
                - 첫째 줄: 도시의 개수 N (1 ≤ N ≤ 20)
                - 둘째 줄: N x N 행렬의 형태로 거리 정보. 
                  (행렬의 i행 j열은 도시 i에서 도시 j까지의 거리)
                
                출력:
                - 최소 비용
            

문제 접근 방법

이 문제의 해결을 위해 다이나믹 프로그래밍(Dynamic Programming)과 비트 마스킹(Bit Masking) 기법을 사용합니다.
다이나믹 프로그래밍을 통해 서브 문제를 해결하고, 비트 마스킹을 통해 도시 방문 여부를 관리합니다.
N개의 도시가 있을 때, 각 도시의 방문 상태는 비트로 표현할 수 있습니다.
예를 들어, N=4의 경우 0000은 어떤 도시도 방문하지 않은 상태, 1111은 모든 도시를 방문한 상태를 의미합니다.
이를 통해 각 서브 문제에서 이전에 계산된 값을 활용하여 최소 비용을 계산할 수 있습니다.

알고리즘 설명

1. **비트마스킹 설정**:
각 도시의 상태를 비트로 표현합니다. 예를 들어, 4개의 도시가 있으면 0b0000부터 0b1111까지 표현할 수 있습니다.
이 비트마스크를 사용하여 방문한 도시를 추적할 수 있습니다.

2. **재귀 호출**:
현재 도시와 방문한 도시의 비트마스크를 인자로 받고, 모든 도시를 방문하기 위한 최소 비용을 계산합니다.

3. **메모이제이션**:
이전에 계산한 결과를 저장하여 중복 계산을 줄입니다. 상태는 `(현재 도시, 방문한 도시의 비트마스크)`로 저장합니다.

4. **최종 경로 계산**:
모든 도시를 방문한 경우, 시작 도시로 돌아오는 비용을 더하여 최소 경로를 반환합니다.

C++ 코드 구현

                #include 
                #include 
                #include 
                #include 

                using namespace std;

                int N; // 도시의 개수
                int dist[20][20]; // 거리 행렬
                int dp[1 << 20][20]; // 메모이제이션

                int tsp(int mask, int pos) {
                    // 모든 도시를 방문했으면 시작 도시로 돌아간다
                    if (mask == (1 << N) - 1) {
                        return dist[pos][0]; // 시작 도시로의 거리
                    }

                    // 이미 계산된 결과가 있으면 이를 즉시 반환
                    if (dp[mask][pos] != -1) {
                        return dp[mask][pos];
                    }

                    int ans = INT_MAX; // 초기값은 무한대를 설정
                    for (int city = 0; city < N; city++) {
                        // 도시가 방문되지 않았다면 다음 도시로 이동
                        if ((mask & (1 << city)) == 0) {
                            int newAns = dist[pos][city] + tsp(mask | (1 << city), city);
                            ans = min(ans, newAns);
                        }
                    }

                    return dp[mask][pos] = ans; // 결과 저장
                }

                int main() {
                    // 도시의 개수를 입력받는다
                    cout << "도시의 개수를 입력하세요: ";
                    cin >> N;

                    // 거리 행렬 입력
                    cout << "거리 행렬을 입력하세요:" << endl;
                    for (int i = 0; i < N; i++) {
                        for (int j = 0; j < N; j++) {
                            cin >> dist[i][j];
                        }
                    }

                    // 메모이제이션 배열 초기화
                    memset(dp, -1, sizeof(dp));

                    // 최소 비용 계산 및 출력
                    int result = tsp(1, 0); // 시작할 때 첫 번째 도시를 방문
                    cout << "최소 비용: " << result << endl;

                    return 0;
                }
            

결론

외판원 문제는 알고리즘 및 데이터 구조의 중요한 예제 중 하나로,
다이나믹 프로그래밍 기법을 통해 효과적으로 해결할 수 있습니다.
이 문제를 통해 비트 마스킹과 메모이제이션이 어떻게 결합되어 강력한 해결책을 제공하는지를 이해할 수 있었습니다.
실제 코딩 인터뷰에서도 자주 등장하는 문제이므로 충분한 연습을 통해 숙련도를 높이는 것이 중요합니다.

C++ 코딩테스트 강좌, 오일러 피 함수 구현하기

코딩 테스트 준비 중 수학과 알고리즘 문제에 대한 이해는 매우 중요합니다. 오늘은 오일러 피 함수에 대해 논의하고 이를 C++로 구현하는 방법을 알아보겠습니다. 오일러 피 함수는 주어진 정수 n보다 작거나 같은 양의 정수와 서로소인 정수의 개수를 반환하는 함수입니다. 이는 수론에 많은 응용이 있으며, 수학적 문제를 해결하는 데 유용합니다.

1. 오일러 피 함수 소개

오일러 피 함수는 다음과 같이 정의됩니다:

  • 주어진 n에 대해서, φ(n) = n * (1 – 1/p1) * (1 – 1/p2) * … * (1 – 1/pk),

여기서 p1, p2, … pk는 n의 서로소인 모든 소수입니다. 예를 들어, φ(6)은 다음과 같이 계산됩니다:

  • n = 6, 소수 p = 2, 3
  • φ(6) = 6 * (1 – 1/2) * (1 – 1/3) = 6 * 1/2 * 2/3 = 2

1.1 오일러 피 함수의 성질

  • φ(1) = 1
  • 만약 p가 소수이고 k가 양의 정수일 때, φ(p^k) = p^k * (1 – 1/p)
  • n의 두 수 a, b가 서로소일 때, φ(ab) = φ(a) * φ(b)

2. 문제 설명

문제: 주어진 정수 n에 대해 오일러 피 함수를 계산하는 C++ 프로그램을 작성하시오.

입력: 정수 n (1 ≤ n ≤ 106)

출력: 정수 φ(n)

3. 알고리즘 설계

오일러 피 함수를 직접 계산하는 방법은 비효율적일 수 있습니다. 소수를 미리 구한 후 위에서 정의한 식을 이용하여 φ(n)을 계산할 수 있습니다. 이를 위해 다음과 같은 단계로 알고리즘을 설계합니다.

  1. 먼저, 에라토스테네스의 체를 사용하여 n 이하의 모든 소수를 구합니다.
  2. 구한 소수를 이용해 φ(n)을 계산합니다.

3.1 에라토스테네스의 체

에라토스테네스의 체는 소수를 신속하게 찾기 위한 고전적인 알고리즘입니다. 이 알고리즘은 시간 복잡도가 O(n log log n)으로 매우 효율적입니다.

4. C++ 코드 구현

이제 전체 알고리즘을 C++ 코드로 구현해 보겠습니다. 다음은 오일러 피 함수를 계산하는 C++ 코드입니다.

#include <iostream>
#include <vector>

using namespace std;

// 오일러 피 함수 계산
int eulerPhi(int n) {
    int result = n; // 초기값은 n
    for (int i = 2; i * i <= n; i++) {
        // 만약 i가 n의 약수라면
        if (n % i == 0) {
            // 소수를 곱해서 결과를 조정합니다
            while (n % i == 0) {
                n /= i;
            }
            result -= result / i; // 결과 계산
        }
    }
    // 마지막에 남은 n이 소수일 경우
    if (n > 1) {
        result -= result / n; // 소수에 대한 결과 처리
    }
    return result;
}

int main() {
    int n;
    cout << "정수를 입력하세요: ";
    cin >> n;
    
    cout << "φ(" << n << ") = " << eulerPhi(n) << endl;
    return 0;
}

5. 코드 설명

위 코드는 다음과 같은 단계로 작동합니다:

  • eulerPhi(int n) 함수는 주어진 정수 n에 대해 오일러 피 함수를 계산하고 반환합니다.
  • 변수 result는 초기값으로 n을 가지며, 소수가 발견될 때마다 이 값을 업데이트합니다.
  • 소수 i가 n의 약수일 경우, n을 i로 나누어가며 i의 배수를 제거합니다. 이 과정에서 소수에 따라 결과를 조정합니다.
  • 모든 소수를 검사한 후, 만약 n이 1보다 큰 경우 (즉, n이 소수인 경우) 추가로 처리합니다.

6. 코드 테스트

코드를 완료한 후, 다양한 테스트 케이스로 함수를 검증해 볼 수 있습니다. 예를 들면:

  • n = 1일 때, φ(1) = 1
  • n = 6일 때, φ(6) = 2
  • n = 9일 때, φ(9) = 6

7. 성능 분석

위 알고리즘은 O(√n)의 시간복잡도를 가지고 있으며, n이 최대 106일 때도 상대적으로 빠르게 작동합니다. 공간 복잡도는 O(1)로 추가적인 메모리 사용이 거의 없습니다. 이러한 이유로 대규모 데이터에서도 효율적으로 사용될 수 있습니다.

8. 결론

오늘의 포스트에서는 오일러 피 함수의 개념과 이를 C++로 구현하는 방법을 배웠습니다. 오일러 피 함수는 다양한 수학적 문제의 해결에 유용하게 사용될 수 있으며, 컴퓨터 프로그래밍에서 큰 역할을 합니다. 이러한 문제를 풀어보는 것은 코딩 테스트 준비에 큰 도움이 될 것입니다.

코드에 대한 질문이나 피드백이 있다면 댓글로 남겨 주세요! 다음 포스트에서는 또 다른 알고리즘 문제를 다룰 예정입니다. 감사합니다!