문제 개요
n개의 양의 정수로 이루어진 연결 리스트가 주어졌을 때, 리스트에 포함된 소수(prime number) 중에서 값이 가장 작은 소수와 가장 큰 소수를 찾아야 합니다.
예를 들어 다음과 같은 리스트가 주어진 경우를 살펴보겠습니다.
10 -> 4 -> 1 -> 12 -> 13 -> 7 -> 6 -> 2 -> 27 -> 33
이 경우 최소 소수는 2이고, 최대 소수는 13입니다.
여기서 10, 4, 1, 12, 6, 27, 33은 모두 소수가 아니므로 후보에서 제외되며, 남은 13, 7, 2 중에서 최솟값과 최댓값을 구하게 됩니다.
알고리즘
이 문제는 에라토스테네스의 체(Sieve of Eratosthenes)를 활용하면 효율적으로 해결할 수 있습니다. 전체 과정은 다음과 같습니다.
- 연결 리스트에 담긴 숫자들 중 최댓값을 구합니다. 이 값을
maxNumber라고 부릅니다. - 1부터
maxNumber까지의 범위에서 소수 여부를 판별하는 불리언(Boolean) 배열을 생성합니다. 인덱스가 소수이면true, 아니면false가 저장됩니다. - 연결 리스트를 처음부터 끝까지 순회하면서 각 노드의 값이 소수인지 배열을 통해 확인하고, 그중 최솟값과 최댓값을 갱신합니다.
소수 판별을 매번 반복 계산하는 대신 한 번의 체 생성으로 처리하기 때문에, 리스트의 길이가 길어져도 빠르게 동작한다는 장점이 있습니다.
예제 코드
다음은 위 알고리즘을 C++로 구현한 전체 코드입니다.
#include <iostream>
#include <vector>
#include <climits>
#include <algorithm>
#include <list>
#define SIZE(arr) (sizeof(arr) / sizeof(arr[0]))
using namespace std;
void printMinAndMaxPrimes(list<int> intList) {
// 리스트에서 최댓값을 구함
int maxNumber = *max_element(intList.begin(), intList.end());
// 에라토스테네스의 체로 소수 테이블 생성
vector<bool> primes(maxNumber + 1, true);
primes[0] = primes[1] = false;
for (int p = 2; p * p <= maxNumber; ++p) {
if (primes[p]) {
for (int i = p * 2; i <= maxNumber; i += p) {
primes[i] = false;
}
}
}
// 리스트를 순회하며 최소/최대 소수 찾기
int minPrime = INT_MAX;
int maxPrime = INT_MIN;
for (auto it = intList.begin(); it != intList.end(); ++it) {
if (primes[*it]) {
minPrime = min(minPrime, *it);
maxPrime = max(maxPrime, *it);
}
}
cout << "Prime number of min value = " << minPrime << "\n";
cout << "Prime number of max value = " << maxPrime << "\n";
}
int main() {
int arr[] = {10, 4, 1, 12, 13, 7, 6, 2, 27, 33};
list<int> intList(arr, arr + SIZE(arr));
printMinAndMaxPrimes(intList);
return 0;
}
코드 설명
- 최댓값 탐색: STL의
max_element함수를 사용해 리스트 전체에서 가장 큰 값을 한 번에 구합니다. - 소수 테이블 생성:
vector<bool>을 모두true로 초기화한 뒤, 0과 1은 소수가 아니므로false로 설정합니다. 이후 2부터 시작해 제곱근까지만 확인하면서 해당 수의 배수들을 모두 지워 나갑니다. - 최종 순회: 초기값을 각각
INT_MAX와INT_MIN으로 설정해 두면, 어떤 입력이 들어와도 안전하게 비교할 수 있습니다.
실행 결과
위 프로그램을 컴파일하고 실행하면 다음과 같은 결과가 출력됩니다.
Prime number of min value = 2
Prime number of max value = 13
시간 복잡도
에라토스테네스의 체 생성에는 O(N log log N)의 시간이 걸리고(N은 리스트 내 최댓값), 리스트 순회에는 O(n)의 시간이 걸립니다(n은 노드 개수). 따라서 전체 시간 복잡도는 O(N log log N)이며, 추가로 사용하는 공간은 소수 테이블을 위한 O(N)입니다.