본문 바로가기

알고리즘

백준 알고리즘 문제 풀이 가이드: 코딩 면접 대비 완벽 준비-4134 다음 소수 편 (python)

728x90
반응형

문제 살펴보기!!

문제 링크 : https://www.acmicpc.net/problem/4134


반응형

솔루션 살펴보기!!

def is_prime(n):
    # n이 2보다 작으면 소수가 아님
    if n < 2:
        return False
    
    # 2, 7, 61에 대해 나눠떨어지는지 체크 (특정 작은 소수에 대해 직접 확인)
    for p in [2, 7, 61]:
        if n % p == 0:
            return n == p
    
    # n-1 = d * 2^s 형태로 변환
    d = n - 1
    s = 0
    while d % 2 == 0:
        d //= 2
        s += 1
    
    # 미르만-라빈 소수 판정법 적용
    for a in [2, 7, 61]:
        if a >= n:
            continue
        
        x = pow(a, d, n)
        if x == 1 or x == n - 1:
            continue
        
        # 제곱을 반복하여 소수 여부를 판정
        for _ in range(s - 1):
            x = pow(x, 2, n)
            if x == n - 1:
                break
        else:
            return False
    
    return True

def next_prime(n):
    # n이 2 이하인 경우 2 반환
    if n <= 2:
        return 2
    
    # n이 짝수면 다음 홀수부터 검사 시작
    if n % 2 == 0:
        n += 1
    
    # 홀수 단위로 증가시키면서 소수 여부 판정
    while not is_prime(n):
        n += 2
    
    return n

def main():
    # 입력 처리 및 소수 찾기
    T = int(input().strip())  # 테스트 케이스 개수
    for _ in range(T):
        n = int(input().strip())  # 주어진 수 n
        print(next_prime(n))  # n보다 크거나 같은 다음 소수 출력

if __name__ == "__main__":
    main()

주요 코드 설명

  1. is_prime 함수:
    • n < 2: 2보다 작은 수는 소수가 아니므로 False 반환.
    • [2, 7, 61]: 이 작은 소수로 먼저 나눠서 나눠 떨어지면 소수 여부를 빠르게 판정.
    • d와 s 계산: n-1을 d * 2^s 형태로 분해.
    • 미르만-라빈 테스트: 소수 판정을 위한 반복 제곱 검사.
  2. next_prime 함수:
    • 입력값이 2 이하일 때는 바로 2 반환.
    • 짝수일 경우 다음 홀수부터 소수 여부를 검사.
    • while 루프: 소수가 될 때까지 홀수 단위로 증가하면서 is_prime을 통해 검사.
  3. main 함수:
    • 테스트 케이스 개수를 입력받고, 각 테스트 케이스에 대해 next_prime 함수를 호출하여 소수 결과를 출력.

풀이 전략 및 주요 코드 흐름

  1. 문제 이해 및 요구사항 분석:
    • 입력으로 주어진 정수 n보다 크거나 같은 첫 번째 소수를 찾아야 합니다.
    • 소수를 찾기 위해 소수 판정 알고리즘과 다음 소수를 찾는 반복 로직을 구현해야 합니다.
  2. 풀이 전략:
    • 소수 판정: 미르만-라빈 소수 판정법을 사용하여 n이 소수인지 판별합니다. 이 알고리즘은 특정 작은 소수([2, 7, 61])를 기반으로 하여, 오차를 최소화하며 소수 판정 속도를 높입니다.
    • 다음 소수 찾기: 주어진 n부터 시작하여 홀수 단위로 증가하면서 소수 여부를 검사하여 가장 가까운 소수를 찾습니다.
  3. 주요 코드 흐름:
    • is_prime 함수: 입력된 n이 소수인지 판정합니다.
      • 2보다 작은 경우는 소수가 아니라고 판정.
      • n이 2, 7, 61 중 하나로 나누어떨어지는지 확인하여 소수 여부를 먼저 빠르게 판별.
      • 미르만-라빈 알고리즘을 통해 더 큰 수에 대해 소수 여부를 검증.
    • next_prime 함수: 주어진 n보다 크거나 같은 다음 소수를 찾습니다.
      • nn이 2 이하이면 바로 2를 반환.
      • 홀수 단위로 증가시키면서 is_prime을 사용해 소수 여부를 확인하여 결과를 반환.
    • main 함수: 입력을 처리하고 각 테스트 케이스에 대해 next_prime 함수를 호출해 결과를 출력합니다.
      • 입력받은 T개의 테스트 케이스에 대해 각각 n을 받아서, 해당 n보다 크거나 같은 소수를 출력합니다.

코드 면접시 알아야할 주요 개념

이 코드와 관련된 코드 면접에서 중요하게 다룰 수 있는 개념들은 다음과 같습니다. 이는 소수 판정 문제와 관련된 알고리즘, 최적화 기법, 그리고 일반적인 프로그래밍 개념을 포함합니다:

1. 소수 판정 알고리즘 (Primality Testing)

  • 미르만-라빈 소수 판정법 (Miller-Rabin Primality Test):
    • 이 알고리즘은 확률적 소수 판정법으로, 특정한 기반 숫자 집합에 대해 높은 확률로 소수를 판정할 수 있습니다.
    • 코드에서 사용하는 [2, 7, 61]은 이 알고리즘의 기반 숫자들로, 64비트 정수 범위에서 충분히 정확하게 소수를 판정할 수 있는 값입니다.
    • 알고리즘의 핵심은 n-1을 2^s * d 형태로 분해하고, 특정한 조건을 만족하는지 반복적으로 확인하는 것입니다.
    • 면접에서 이 알고리즘을 사용하는 이유와 기본적인 원리에 대해 설명할 수 있어야 합니다.

2. 시간 복잡도 분석 (Time Complexity Analysis)

  • 소수 판정의 시간 복잡도:
    • 미르만-라빈 테스트의 시간 복잡도는 일반적으로 O(klog⁡3n)O(k \log^3 n)로, kk는 테스트 횟수입니다. 이때, k는 코드에서 [2, 7, 61]의 길이로, 고정된 값입니다.
    • next_prime 함수에서 소수를 찾기 위해 반복문을 사용하며, 이때 각 수를 소수 판정하는 비용이 누적됩니다.
  • 최악의 경우 분석:
    • 소수 사이의 간격이 좁으면 빠르게 다음 소수를 찾을 수 있지만, 간격이 넓은 경우 더 많은 수를 탐색해야 합니다. 이 점에 대해 설명할 수 있어야 합니다.

3. 수학적 개념 (Mathematical Concepts)

  • 페르마의 소정리거듭제곱 모듈 연산 (Modular Exponentiation):
    • 소수 판정에 사용되는 기본 원리로, 특정 수 a에 대해 an−1mod  n=1a^{n-1} \mod n = 1이 성립하는지를 확인합니다.
    • 이 코드에서 pow(a, d, n)를 사용하여 효율적으로 거듭제곱 모듈 연산을 수행합니다.
    • 이러한 수학적 배경 지식을 이해하고, 왜 이러한 원리를 소수 판정에 사용하는지 설명할 수 있어야 합니다.

4. 코드 최적화 (Code Optimization)

  • 홀수만 검사하는 로직:
    • 코드에서 짝수는 소수가 될 수 없으므로, 다음 소수를 찾을 때 n을 2씩 증가시키는 방식으로 짝수를 건너뜁니다.
    • 이는 탐색 공간을 절반으로 줄여 성능을 크게 향상시키는 기법입니다.
  • 사전 필터링:
    • 2, 7, 61과 같은 작은 소수에 대해 먼저 나눠서 체크하는 것은 빠르게 특정 수가 소수인지 판별하는 데 유용합니다.
    • 이는 미르만-라빈 테스트를 직접 적용하기 전에 불필요한 연산을 줄일 수 있게 해줍니다.

5. 입출력 최적화 (Input/Output Optimization)

  • 입력 처리 방식:
    • 입력이 여러 줄로 주어질 때, sys.stdin.read를 사용하면 성능이 좋지만, 코드의 간결성을 위해 input()을 여러 번 사용하는 것도 나쁘지 않습니다.
    • 면접에서는 입력 처리 방식을 선택할 때 성능과 간결성 사이의 트레이드오프를 이해하고 설명할 수 있어야 합니다.

6. 반복문과 조건문 사용의 효율성

  • 반복문 내 조건 사용:
    • for _ in range(s - 1)와 같은 반복문은 소수 판정 과정에서 반복적인 제곱 계산을 수행합니다. 이때, 조기 탈출(break)을 통해 효율성을 높이는 로직이 포함되어 있습니다.
    • 면접에서는 이러한 반복문 사용의 이유와 조기 탈출을 통한 효율성 향상을 설명할 수 있어야 합니다.

7. 에지 케이스 (Edge Cases) 처리

  • n이 2 이하일 때:
    • n이 2보다 작을 때 2를 반환하는 로직은 중요한 에지 케이스 처리입니다.
    • 면접에서는 소수 판정 문제에서 흔히 발생하는 에지 케이스, 예를 들어 n이 0, 1, 또는 매우 큰 숫자일 때의 처리 방법을 설명할 수 있어야 합니다.

8. 알고리즘 선택 이유 및 대안 비교

  • 미르만-라빈 테스트 vs. 에라토스테네스의 체:
    • 면접에서는 특정 문제에 대해 왜 미르만-라빈 소수 판정법을 사용했는지 설명하고, 다른 알고리즘 (예: 에라토스테네스의 체)과의 비교를 할 수 있어야 합니다.
    • 에라토스테네스의 체는 많은 수에 대해 소수를 한 번에 찾을 때 유리하지만, 미르만-라빈 테스트는 특정 수 하나의 소수 여부를 확인하는 데 적합합니다.
728x90
반응형