효율적으로 약수 구하기 - O(√N)

SEPTEMBER·2025년 1월 8일

오늘은 효율적으로 약수를 구하는 방법에 대해 알아보겠습니다. 먼저 기본적인 방법으로 약수를 구해보고, 이후에 좀 더 효율적인 방법으로 접근하여 약수를 구하고 시간 복잡도를 줄이는 과정을 보여드리겠습니다.

기본적인 약수 구하는 방법

어떤 수 𝑁의 약수를 구하는 가장 기본적인 방법은 1부터 𝑁까지 모든 수를 나누어 나머지가 0이 되는 수를 찾는 것입니다. 아래 코드와 같이 1부터 𝑁까지 루프를 돌면 쉽게 결과를 도출할 수 있습니다.

  // O(N) 방식 - 비효율적
  for (int i = 1; i <= N; i++) {
      if (N % i == 0) {
          System.out.println(i);
      }
  }
  • 시간 복잡도: 𝑂(𝑁)

하지만 이와 같은 방법은 모든 수를 검사해야 하므로 큰 수일수록 실행 시간이 오래 걸리며, 앞으로 설명드릴 방법보다 효율적이지 않습니다.


효율적으로 약수 구하는 방법

약수는 항상 '쌍'으로 존재한다는 사실을 알면, 어떤 수 𝑁의 약수를 구하기 위해 1부터 √N 까지 수만 나누어 떨어지는지 확인하면 되기 때문에 보다 효율적으로 약수를 구할 수 있습니다. 또한 입력 크기가 커질수록 기존 𝑂(𝑁) 방식보다 훨씬 빠르게 결과를 도출할 수 있습니다.

	// O(√N) 방식 - 효율적
	for (int i = 1; i * i <= N; i++) {  // √N까지만 검사
        if (N % i == 0) {  // i가 약수라면
            System.out.println(i);  // 작은 약수 출력
            if (i != N / i) {  // 중복 방지 (제곱수인 경우)
                System.out.println((N / i));  // 대응하는 큰 약수 출력
            }
        }
    }
  • 시간 복잡도: O(√N)

코드 자체는 for문과 if문으로 작성되었기 때문에 이해하기 어렵지 않으리라 생각됩니다. 하지만 약수의 특징은 단순한 서술만으로 이해하기 어려울 수 있으므로 구체적인 예시를 들어 설명하겠습니다.

1. 약수는 항상 '쌍'으로 존재

  • (예시) 𝑁 = 36인 경우, 약수의 쌍

    (1,36), (2,18), (3,12), (4,9), (6,6)

  • 즉, 약수를 찾을 때 한쪽 약수만 찾으면 다른 약수는 자동으로 구할 수 있음

  • 따라서 √N 까지만 검사하면 모든 약수를 찾을 수 있음

  • N = 36일 때, √36 = 6 이므로 1부터 6까지만 검사하면 모든 약수를 구할 수 있음

  • 만약 𝑖가 𝑁을 나누어 떨어지게 만들면, 그에 대응하는 𝑁 / 𝑖도 반드시 약수가 됨

2. 제곱수인 경우 중복 값에 주의

  • N = 36이라면 (6,6)처럼 중복되는 약수가 발생할 수 있음

  • 따라서, i != N / i 조건을 사용하여 중복을 방지함


시간 복잡도 정리

방법시간 복잡도설명
단순 반복문𝑂(𝑁)1부터 𝑁까지 모두 검사
√NO(√N)약수의 쌍을 활용하여 빠르게 연산

0개의 댓글