알고리즘/정수론

[약수구하기] 시간복잡도 조금이라도 줄여보기

hyomin1 2024. 3. 26. 21:07

코딩 테스트 문제를 풀다보면 약수를 이용한 문제가 간혹 나온다.

평소에 생각없이 약수 문제를 풀때는

public class Main {
    public static void main(String[] args) {
        
        int[] div = new int[5];
        int idx = 0;
        for(int i = 1; i <= 5; i++) {
            int count = 0;
            for(int j = 1; j <= i; j++) {
                if(i % j == 0) {
                    count++;
                }
            }
            div[idx++] = count; 
        }
    }
}

 

1부터 5까지의 약수를 구해서 각각의 약수의 개수를 배열에 넣어주는 코드인데 이런식으로 모든 수에 대해 1부터 해당 수까지 모두 나누어보는 방식으로  주어진 범위가 작을땐 괜찮았지만 범위가 커졌을때 시간복잡도가 O(N*N)으로 시간초과가 나는 경우가 있었다.

 

그래서 시간을 조금이라도 단축시키고자 방법을 찾아보니 약수는 대칭적이다.

9의 약수를 구한다고 하면 1과 9 3과 3 이런식으로 해당수의 제곱근까지만 찾아보고 개수를 2개씩 증가시켜주면 된다.

9같은 경우는 제곱수이므로 제곱수의 경우는 중복 약수가 있으므로 개수를 1개 감소시켜주면된다. 

제곱근까지만 나누어보면 시간 복잡도가 O(N√N)으로 상당히 줄어들게 된다.

 

public class Main {
    public static void main(String[] args) {

        int[] div = new int[5];
        int idx = 0;
        for(int i = 1; i <= 5; i++) {
            int count = 0;
            int sq = (int)Math.sqrt(i);
            for(int j = 1; j <= sq; j++) {  //해당 수의 제곱근까지만 탐색
                if(i % j == 0) {
                    count+=2;
                }
            }
            if(sq * sq == i) { //제곱수인 경우 중복약수 제거
                count--;
            }
            div[idx++] = count;
        }
    }
}