알고리즘

[소인수] 구하기(Kotlin)

Developer성현 2025. 1. 16. 02:59

소인수: 어떤 수의 약수 중 소수인 수

예: 12의 소인수 = 2, 3

 

이 방식은 제곱근 범위탐색 으로 약수를 순서대로 구한 후 소수인지 판별을 해서 중복값을 허용하지 않는 Set 에 담는 방식입니다.

fun main() {
    val num = readlnOrNull()?.toInt() ?: 0
    val primeDivisors = mutableSetOf<Int>()

    for (i in 1..sqrt(num.toDouble()).toInt()) {
        if (num % i == 0) {
            if (isPrime(i)) primeDivisors.add(i)
            if (i != num / i && isPrime(num / i)) primeDivisors.add(num / i)
        }
    }

    println(primeDivisors.sorted().joinToString(", "))
}

// 소수를 확인하는 함수
fun isPrime(number: Int): Boolean {
    if (number < 2) return false
    for (i in 2..sqrt(number.toDouble()).toInt()) {
        if (number % i == 0) return false
    }
    return true
}

시간 복잡도:

약수 구하기: O( (n) )

소수 판별: O( (n) )

정렬함수: 자바에서 사용하는 함수를 그대로 오버라이딩 해서 사용하는거 같은데 어떤 알고리즘을 사용하는지는 잘 몰겠습니다...

일단 약수 하나를 구하고 소수를 판별하니 O( (n) * (n) ) = O(n) 정도가 되는거 같습니다.

 

1. 에라토스테네스의 체 를 활용한 소인수 구하기

사전에 구하고자 하는 수까지의 모든 소수를 미리 구한 후 약수들과 나누었을 때 나머지가 0 인 소수들만 리스트에 추가합니다.

fun main() {
    val num = readlnOrNull()?.toInt() ?: 0
    val primes = sieveOfEratosthenes(num)
    val primeDivisors = mutableListOf<Int>()

    for (prime in primes){
        if(prime > kotlin.math.sqrt(num.toDouble())) break
        if(num % prime == 0) primeDivisors.add(prime)
    }

    println(primeDivisors.joinToString(", "))
}

fun sieveOfEratosthenes(limit: Int): List<Int> {
    val isPrime = BooleanArray(limit + 1) { true }
    isPrime[0] = false
    isPrime[1] = false

    for (i in 2..sqrt(limit.toDouble()).toInt()) {
        if (isPrime[i]) {
            for (j in i * i..limit step i) {
                isPrime[j] = false
            }
        }
    }
    return isPrime.toList().mapIndexedNotNull { index, prime -> if (prime) index else null }
}

시간복잡도: O( (n) )

 

2. 소인수 구하기 방법2

이 방법은 제곱근 범위탐색으로 소수를 찾은 후 해당 소수가 리스트에 존재하지 안는다면 추가한 후 입력값을 해당 소수로 나누어 떨어지지 안을 때까지 나누게 됩니다. 나누어 떨어지지 안는다면 다음 소수를 찾아 동일한 과정을 반복하여 소인수를 구할 수 있습니다.

val num = readlnOrNull()?.toInt() ?: 0
var tempNum = num
val primeDivisors = mutableListOf<Int>()

for (i in 2..sqrt(tempNum.toDouble()).toInt()) {
    while (tempNum % i == 0) {
        if (!primeDivisors.contains(i)) primeDivisors.add(i)
        tempNum /= i
    }
}
if (tempNum > 1) primeDivisors.add(tempNum) // 남은 숫자가 소수일 경우 추가
println(primeDivisors.joinToString(", "))

시간복잡도: O( (n)​ * log(n) )

 

소인수를 구하는 알고리즘 3가지를 알아보았습니다. 이중에서 시간 복잡도가 적은것은 에라토스테네스의 체를 활용한 방법인거 같네요. 하지만 코드량은 2번째 방법이 더 적고 메모리 사용량도 적다는 장점이 있습니다.