Home [Algorithm] 유클리드 호제법(Euclidean Algorithm): 최대공약수(GCD)와 최소공배수(LCM) 구하기
Post
Cancel

[Algorithm] 유클리드 호제법(Euclidean Algorithm): 최대공약수(GCD)와 최소공배수(LCM) 구하기

유클리드 호제법(Euclidean Algorithm)

유클리드 호제법이란, 두 개의 양의 정수에 대해 최대공약수(GCD, greatest common divisor)를 구하는 알고리즘이다.

“호제법”이라는 것은 두 수가 서로 상대방 수를 나누어 원하는 수를 얻는 알고리즘을 의미한다.


유클리드 호제법의 내용을 간단히 정리하면 다음과 같다.

두 양의 정수 $a, b \space (a>b)$에 대하여 $a=b \cdot t+r$ $(0\le r<b)$, 즉 $r =a\mod b$ 라고 하자. 이때,

  • $r=0$이라면, $\gcd (a, b)=b$이다.

  • 그렇지 않다면, $\gcd(a, b)=\gcd(b, r)$이다.


이러한 유클리드 호제법을 이용하여 두 양의 정수의 최대공약수최소공배수를 구할 수 있다. 각 방법을 알아보기 전에, 어떻게 유클리드 호제법을 증명할 수 있는지 살펴보자.


증명

$r=a \mod b$이고 $a=b\cdot t +r$일때, $\gcd(a, b)=\gcd(b, r)$ 임을 증명해보자.

  1. 우선, $d=\gcd(a,b)$로 가정한다.

    기본 정의에 의해 $a$와 $b$는 모두 $d$로 나누어떨어지는데, $a =b\cdot t+r$이므로 $r$ 또한 $d$로 나누어떨어지게 된다.

    즉, $b$와 $r$이 모두 $d$로 나누어떨어지므로, $\gcd(b,r)$은 $\gcd(a, b)$(== $d$)로 나누어떨어진다.

  2. 이어서 $c=\gcd(b, r)$로 가정한다.

    기본 정의에 의해 $b$와 $r$은 모두 $c$로 나누어떨어지는데, $a=b\cdot t+r$이므로 $a$ 또한 $c$로 나누어떨어지게 된다.

    즉, $a$와 $b$가 모두 $c$로 나누어떨어지므로, $\gcd(a,b)$는 $\gcd(b,r)$(== $c$)로 나누어떨어진다.


이를 모두 종합해보면 $\gcd(a,b)$와 $\gcd(b,r)$이 서로의 값으로 나누어떨어지기 때문에, $\gcd(a,b)=\gcd(b,r)$ 임을 확인할 수 있다.


최대공약수(GCD) 구하기 (in Python)

개념적으로 접근하면 다음과 같이 재귀적으로 함수를 작성할 수 있다.

1
2
3
4
5
def gcd(a, b):
    if (r := a % b) == 0:
        return b
    else:
        return gcd(b, r)


이를 반복문(w/ 파이썬 다중 할당)으로 바꾸면 다음과 같다.

1
2
3
4
def gcd(a, b):
    while b != 0:
        a, b = b, a % b
    return a


또한, 시간 복잡도는 $O(\log(\min(a,b)))$이다. 이에 대한 자세한 유도 과정은 링크1, 링크2를 참고한다.


이때, gcd(a, b) 함수에서 $a$와 $b$의 입력 순서가 꼭 $a>b$일 필요는 없다. 왜냐하면 $a <b$인 경우일지라도, 첫 나머지 $r$을 구하고 $b$와 $r$로 입력 값을 바꿈으로써 그 순서가 맞추어지게 되기 때문이다.

다음과 같이 입력 값의 순서를 바꾸어서 각 단계마다 값을 출력해보면 동작을 확인할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
print(gcd(1071, 1029))
# a=1071 / b=1029
# a=1029 / b=42
# a=42 / b=21
# 21

print(gcd(1029, 1071))
# a=1029 / b=1071
# a=1071 / b=1029
# a=1029 / b=42
# a=42 / b=21
# 21


최소공배수(LCM) 구하기 (in Python)

두 양의 정수의 최소공배수(LCM, least common multiple)를 구하려면, 두 수를 곱한 값을 최대공약수로 나누면 된다.

두 양의 정수의 곱은 두 수의 최대공약수와 최소공배수의 곱으로 나타낼 수 있다.

\[a\times b=\gcd(a, b) \times \text{lcm}(a,b)\]


즉, 다음과 같은 순서로 로직을 작성할 수 있다.

  1. 유클리드 호제법을 통해 두 수의 최대공약수를 구한다.
  2. 두 수의 곱을 1번에서 구한 최대공약수로 나눈다.


1
2
def lcm(a, b):
    return a * b // gcd(a, b)


References

This post is licensed under CC BY 4.0 by the author.

[OOP] SOLID 원칙

[Better Way #52] 자식 프로세스를 관리하기 위해 subprocess를 사용하라