최대 공약수(GCD) 알고리즘 - 유클리드 호제법
업데이트:
서론
프로그래머스에서 멀쩡한 사각형이라는 문제를 풀다가 거의 두 시간 만에 규칙을 찾아냈는데, 그 규칙이 바로 최대 공약수였다. 최대 공약수와 최소 공배수의 개념은 알지만 이를 구현해 본 적이 없었기에 이번 포스팅을 통해서 정확하게 짚고 넘어가야겠다.
최대 공약수(GCD) 구하기
최대 공약수(GCD, Greatest Common Divisor
)란 두 자연수의 공통된 약수 중에서 가장 큰 수를 의미한다.
- ex) GCD(8, 12) = 4
기존의 GCD 구하는 방법 (Brute force, 무차별 대입)
- 두 자연수 중에서 작은 자연수를 선택
- min(8, 12) => 8선택
- 2부터 8까지 모든 수로 두 수를 나누다가 동시에 0으로 떨어지는 가장 큰 수를 구한다.
1
2
3
4
5
6
7
public static int gcd(int a, int b) {
int result = 0;
for(int i = 1; i <= b; i++) {
if(a % i == 0 && b % i == 0) result = i;
}
return result;
}
- 시간복잡도 : O(N)
유클리드 호제법(Euclidean Algorithm)
유클리드 호제법이란 간단하게 O(logN)
의 시간복잡도로 두 자연수의 최대 공약수를 구할 수 있는 알고리즘이다.
기존의 방법도
O(N)
의 시간복잡도로 나쁘지는 않지만 효율을 높히기 위해 이 알고리즘을 사용한다.
- a를 b로 나눈 나머지를 r이라고 할때 (단, a > b) a와 b의 최대 공약수는 b와 r의 최대 공약수와 같다는 성질을 이용한다.
- 이런 성질을 통해서 b와 r의 최대 공약수 r0를 구하고, 다시 r을 r0로 나눈 나머지를 구하는 과정을 반복하여(
recursive
) 나머지가 0이 되었을 때의 그 몫이 a와 b의 최대 공약수이다. -
이를 수식으로 나타내면 아래와 같다.
1 2 3
GCD(A, B) = GCD(B, A%B) if A%B = 0 -> GCD = B else GCD(B, A%B)
CODE
1
2
3
4
public static int gcd(int a, int b) { // a > b 일때
if(b == 0) return a; // gcd를 찾았다면 그 몫을 return
else return gcd(b, a % b);
}
최소 공배수(LCM) 구하기
최소 공배수(LCM, Least Common Muliple
)란 두 자연수의 공통된 배수 중 가장 작은 수를 의미한다.
-
ex) LCM(8, 12) = 24
-
최소 공배수 = 두 자연수의 곱 / 최대 공약수 ( LCM = a x b / GCD )
CODE
1
2
3
public static int lcm(int a, int b, int gcd) {
return (a * b) / gcd
}