최대공약수를 알기 위해서는 약수(Divisor) 를 알아야한다.
약수는 자연수 A, B가 있을 때, 두 수 A, B를 나누어 떨어지게 만드는 수를 말한다.
최대공약수는 당연히 그 약수 중 제일 큰 수를 말한다.
자! 근데 우리는 A, B가 주어졌을 때 어떻게 최대공약수를 알 수 있을까???
직관적이게 구현해볼까요??
PY</>
a, b = map(int, input().split())result = []for i in range(1, max(a, b)+1): if a % i == b % i == 0: result.append(i)print(result[-1])
(이미지가 생각보다 많이 작네요..ㅎㅎ)
자 이렇게 최대공약수를 얻는 코드를 작성해보았습니다.
그런데 이 코드는 O(max(a, b))의 시간복잡도를 가지고 있죠??
하지만 암호학에서는 진짜 뭔 말도 안되는 큰 수들이 왔다갔다 거립니다…
이보다 더 빠른 알고리즘을 설계해 볼까요?
이때 사용할 알고리즘은 무엇이냐! 바로 유클리드 호제법(Euclidean algorithm) 을 사용할 겁니다!
유클리드 호제법
2개의 자연수(또는 정식) a, b에 대해서 a를 b로 나눈 나머지를 r이라 하면(단, a>b), a와 b의 최대공약수는 b와 r의 최대공약수와 같다.
이 성질에 따라, b를 r로 나눈 나머지 r’를 구하고, 다시 r을 r’로 나눈 나머지를 구하는 과정을 반복하여 나머지가 0이 되었을 때 나누는 수가 a와 b의 최대공약수이다.
요런 유클리드 호제법을 구현해볼까?
PY</>
def gcd_1(a, b): while b != 0: a, b = b, a % b return adef gcd_2(a, b): # 함수 오버헤드 때문에 약간 느릴 수도 return a if not b else gcd_2(b, a % b)
유클리드 호제법을 사용한 최대공약수(GCD) 알고리즘의 시간 복잡도는 ${O(\log(\min(a, b)))}$ 이죠? 굉장히 효율적입니다.
GCD를 이용한 최소공배수(LCM) 구하기
PY</>
def lcm(a, b): return abs(a * b) // gcd(a, b) # overflow를 방지하기 위해서는 a*b를 분리해서 계산하면 됨.