[Java] 약수의 개수를 구하는 효율적인 알고리즘 정리

2025. 7. 16. 17:35·Backend/Java

📖약수 구하기 알고리즘

코딩테스트나 알고리즘 문제를 풀다 보면 약수를 구하는 문제를 자주 만나게 됩니다

하지만 큰 수의 경우 비효율적인 로직으로 인해 시간 초과에 부딪히는 경우가 다반사

이번 글을 통해 약수를 구하는 효율적인 알고리즘을 단계별로 정리해보려고 합니다!!

 


1️⃣일반적인 방법 (O(n))

 

가장 직관적으로 생각할 수 있는 방법은 1부터 n까지 모든 수를 확인하는 것입니다.

// 12의 약수를 구하는 예시
int count = 0;
for (int i = 1; i <= 12; i++) {
    if (12 % i == 0) {
        count++;
    }
}

결과: 12의 약수는 1, 2, 3, 4, 6, 12 총 6개

 

해당 방법은 O(n)의 시간복잡도를 가지므로, n이 커지면 커질수록 오래 걸려서 시간 초과가 발생할 수 있습니다.


1단계 방법의 속도를 개선해 보기 위해 먼저 한 가지 방법을 생각해 보았습니다.

2️⃣절반까지만 확인 + 자기 자신 추가 (O(n/2))

 

n/2까지만 확인하고 마지막에 자기 자신을 추가합니다.

// 12의 약수 구하기
int count = 0;
for (int i = 1; i <= 12 / 2; i++) {  // 6까지만 확인
    if (12 % i == 0) {
        count++;
    }
}
count++; // 자기 자신(12) 추가

결과: 12의 약수는 1, 2, 3, 4, 6, 12 총 6개

 

탐색할 필요가 없는 부분은 제외하여 꽤 많은 속도 개선을 보여주지만 여전히 큰 수에서는 느립니다.


3️⃣제곱근까지만 확인 (O(√n))

 

2단계에서도 여전히 큰 수에서는 속도가 느리기 때문에 로직 자체를 변경해 봅니다.

해결하기 위한 핵심 아이디어는 약수는 항상 쌍을 이룬다는 것입니다.

약수의 쌍 원리

12의 약수를 살펴보면:

  • 1 × 12 = 12
  • 2 × 6 = 12
  • 3 × 4 = 12

이처럼 약수들이 쌍을 이루므로 n/2 보다도 작은 √12 = 3.46... 즉 제곱근까지만 확인 약수를 확인해 나가면 됩니다.


💡왜 제곱근(√n)까지만 확인하면 될까?

제곱근(√n)은 그 수를 둘로 나누는 경계선 역할을 하기 때문입니다.

 

12의 경우를 보면:

  • √12 = 3.46...
  • 12의 약수: 1, 2, 3, 4, 6, 12

제곱근을 기준으로 나누면:

  • √12보다 작은 약수: 1, 2, 3
  • √12보다 큰 약수: 4, 6, 12

또한 작은 약수와 큰 약수가 정확히 쌍을 이룬다는 점 또한 포인트!

  • (1, 12)
  • (2, 6)
  • (3, 4)

결국 √12 이하의 약수(1, 2, 3)를 찾으면, 각각을 12로 나누어서 쌍이 되는 큰 약수들(12, 6, 4)을 자동으로 구할 수 있습니다.

시간복잡도를 O(n)에서  O(√n)으로 획기적으로 줄일 수 있는 것입니다.

 

다만 예외가 존재합니다.


⚠️완전제곱수의 경우 예외

 

완전제곱수의 경우는 다릅니다.
완전제곱수는 어떤 정수의 제곱으로 표현되는 수로, 약수의 개수가 항상 홀수 개입니다.

 

예를 들어 16 ( = 4² )의 경우:

  • 16의 약수: 1, 2, 4, 8, 16
  • 약수 쌍: (1, 16), (2, 8), (4, 4)

여기서 4 × 4 = 16처럼 같은 수끼리 곱해지는 경우가 있습니다. 이때 4는 16의 제곱근이므로 쌍을 이루지 않고 혼자 존재합니다.

 

따라서 제곱근이 존재하는 완전제곱수의 경우, 제곱근에 해당하는 약수는 자신의 쌍과 함께 두 번 카운트하지 않고 한 번만 카운트해야 합니다.

 

💡Java 코드로 적용해보기

int getDivisorCount(int n) {

    int count = 0;
    int sqrt = (int) Math.sqrt(n);
    
    for (int i = 1; i <= sqrt; i++) { // √n까지만 확인
        if (n % i == 0) { // 해당 숫자가 약수인지 먼저 판단
            count++;
            if (i*i != n) { // 약수라면 n의 제곱근인지 확인하고 (자기 자신과 쌍을 이루는 약수)
                count++; // 제곱근이 아니라면 count 증가
            }
        }
    }
    return count;
}

 

이 방법은 O(√n) 시간복잡도를 가지므로 이전 방법들보다 확실히 빠른 성능을 보여줍니다.

n = 10,000일 때:

  • 1단계: 10,000번 반복
  • 2단계: 5,000번 반복
  • 3단계: 100번 반복 (√10,000 = 100)

 

앞으로 약수를 구하는 문제를 만나게 된다면 빠른 속도를 보장하는 해당 알고리즘을 적용해 보는 건 어떨까요?

💡해당 알고리즘을 적용한 문제

 

[프로그래머스, Java] 기사단원의 무기

💡풀이import java.util.stream.IntStream;class Solution { public int solution(int number, int limit, int power) { // 1~number 기사단원으로 분기한다 // 기사번호의 약수의 개수를 구한다. // 약수의 개수가 limit를 초과할경

devoks.tistory.com

 

[프로그래머스, Java] 소수 찾기

💡풀이import java.util.stream.IntStream;class Solution { public int solution(int n) { return (int) IntStream.rangeClosed(2, n) .filter(this::isPrimeNumber) .count(); } boolean isPrimeNumber(int n) { for (int i = 2; i 💡풀이 2📖새로 배운 부

devoks.tistory.com

 

[프로그래머스, Java] 소수 만들기

💡풀이import java.util.ArrayList;import java.util.List;class Solution { public int solution(int[] nums) { int count = 0; for (int a = 0; a 📖새로 배운 부분- 약수의 개수를 구하는 효율적인 알고리즘 정리 글 [Java] 약수의 개

devoks.tistory.com

'Backend > Java' 카테고리의 다른 글

[Java] switch 문 최신 문법까지 정리해보기 (Java 14+)  (0) 2025.07.29
[Java] replace()와 replaceAll()의 차이점  (0) 2025.07.22
[Java] 배열 복사 메서드 간단 정리  (0) 2025.07.15
[Java, String] split() 메서드 정리 - 문자열 자르기  (0) 2025.07.13
[Java, Stack] 왜 Stack이 아닌 Deque로 스택을 구현해야 할까?  (1) 2025.07.10
'Backend/Java' 카테고리의 다른 글
  • [Java] switch 문 최신 문법까지 정리해보기 (Java 14+)
  • [Java] replace()와 replaceAll()의 차이점
  • [Java] 배열 복사 메서드 간단 정리
  • [Java, String] split() 메서드 정리 - 문자열 자르기
devoks
devoks
꾸준히 작성해보자!
  • devoks
    ok's 개발 블로그
    devoks
  • 전체
    오늘
    어제
    • 분류 전체보기 (112) N
      • Backend (15)
        • SpringBoot (0)
        • Java (15)
      • Cs (18) N
      • Infra (0)
        • AWS (0)
        • Docker (0)
      • CodingTest (79)
        • Programmers (79)
  • 링크

    • My GitHub
  • 인기 글

  • 태그

    json
    BufferedReader
    codingtest
    programmers
    CS
    StringTokenizer
    effectivejava
    switch
    java
    BufferedWriter
  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
devoks
[Java] 약수의 개수를 구하는 효율적인 알고리즘 정리
상단으로

티스토리툴바