[프로그래머스] 소수 찾기(Feat. 에라토스테네스의 체)

최민길(Gale)·2023년 7월 7일
1

알고리즘

목록 보기
93/172

문제 링크 : https://school.programmers.co.kr/learn/courses/30/lessons/12921

이 문제는 에라토스테네스의 체 방식으로 풀 수 있습니다. 우선 에라토스테네스의 체에 대해 알아보겠습니다.

에라토스테네스의 체란 소수를 찾는 알고리즘으로, 1부터 N까지 소수의 개수를 구할 때 주로 사용합니다. 우선 2부터 자기 자신을 제외한 배수들을 모두 걸러냅니다. 이후 수를 1씩 증가시키면서 자기 자신을 제외한 배수들을 걸러냅니다. 이 때 이미 걸러진 수를 탐색하지 않아도 되므로 시간이 절약되는 효과를 가집니다.

여기서 구현 시 하나의 팁이 있습니다. 이미 걸러진 수를 탐색하지 않기 위해선 이전에 탐색을 진행한 수의 배수와의 공배수는 피해야 합니다. 예를 들어 이미 2를 탐색한 상황에서 3을 탐색할 경우 두 수의 공배수인 6의 배수는 탐색하지 않아야 한다는 것입니다. 만약 단순히 모든 수를 탐색하면서 소수 판별 여부를 체크했는지 안했는지를 한번 더 체크한다면 체크하는 시간만큼 성능이 떨어지게 됩니다.

따라서 수 i가 소수일 경우 탐색을 진행하는 인덱스는 iXi 부터 i씩 증가시키면서 탐색을 진행하야 합니다. 즉 i X (i+0), i X (i+1), i X (i+2) ... 이런 식으로 탐색을 해야 이전에 탐색을 진행한 수를 체크 여부도 확인하지 않고 넘길 수 있습니다.

이번엔 탐색하는 수의 범위를 고려해보겠습니다. 단순히 2부터 n까지의 수를 직접 비교하는 방법도 있겠지만, 이를 더 최적화할 수 있습니다. 이전 시간에 포스팅을 다룬 기사단원의 무기에서 적용한 방법을 사용할 수 있습니다. 소수는 약수와 연관이 있는 개념이기 때문에 약수의 특징을 이용할 수 있습니다. 약수는 제곱수를 기준으로 서로 매칭되는 특징이 있기 때문에 제곱수보다 큰 수는 체크할 필요가 없습니다. 이를 이 문제에도 적용해본다면 i의 제곱보다 큰 수들에서 걸러지는 배수들은 이미 i의 제곱보다 작은 수들에서 걸러지게 되기 때문에 불필요한 반복만 늘어나게 됩니다. 따라서 범위를 2부터 n/i까지, 즉 i가 2부터 iXi가 n까지 탐색하시면 됩니다.

링크 : https://velog.io/@gale4739/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%A8%B8%EC%8A%A4-%EA%B8%B0%EC%82%AC%EB%8B%A8%EC%9B%90%EC%9D%98-%EB%AC%B4%EA%B8%B0

아래는 코드입니다.

import java.util.*;

class Solution {
    public int solution(int n) {
        int answer = 0;
        boolean[] isNotPrimeNum = new boolean[n+1];
        
        for(int i=2;i*i<=n;i++){
            if(!isNotPrimeNum[i]){
                for(int j=i*i;j<=n;j+=i) isNotPrimeNum[j] = true;
            }
        }
        
        for(int i=2;i<=n;i++){
            if(!isNotPrimeNum[i]) answer++;
        }
        
        return answer;
    }
}

profile
저는 상황에 맞는 최적의 솔루션을 깊고 정확한 개념의 이해를 통한 다양한 방식으로 해결해오면서 지난 3년 동안 신규 서비스를 20만 회원 서비스로 성장시킨 Software Developer 최민길입니다.

0개의 댓글