[Algorithm] 백준(BOJ) - 2609. 최대공약수와 최소공배수 (JAVA) / 유클리드 호제법 알고리즘

최대공약수와 최소공배수

두 개의 자연수를 입력받아 최대 공약수와 최소 공배수를 출력하는 프로그램을 작성하시오.

입력

첫째 줄에는 두 개의 자연수가 주어진다. 이 둘은 10,000이하의 자연수이며 사이에 한 칸의 공백이 주어진다.

출력

첫째 줄에는 입력으로 주어진 두 수의 최대공약수를, 둘째 줄에는 입력으로 주어진 두 수의 최소 공배수를 출력한다.

Example

#1

입력
24 18

출력
6
72

어떻게 푸는게 좋을까?

최대 공약수 (Gratest Common Divisor)

최대공약수는 두 자연수의 공통된 약수 중 가장 큰 수를 의미한다.

최소 공배수 (Least Common Multiple)

최소공배수는 두 자연수의 공통된 배수 중 가장 작은 수를 의미한다.
최소공배수 = 두 자연수의 곱 / 최대공약수

유클리드 호제법

유클리드 호제법 알고리즘을 사용하면 최대 공약수를 빠르게 계산할 수 있다.

유클리드 호제법의 정리는 다음과 같다.

2개의 자연수 a, b에 대해서 a를 b로 나눈 나머지를 r이라 하면(단, a>b), a와 b의 최대공약수는 b와 r의 최대공약수와 같다.
이 성질에 따라, b를 r로 나눈 나머지 r’를 구하고, 다시 r을 r’로 나눈 나머지를 구하는 과정을 반복하여 나머지가 0이 되었을 때 나누는 수가 a와 b의 최대공약수이다. - wikipedia

위 내용을 정리해보자.

a, b ∈ ℤ 이고, r = a mod b 이라고 한다. (r은 a에 b를 나눈 나머지를 의미)
이 때, r은 (0 ≤ r < b) 이고, a ≥ b 이다.

a와 b의 최대공약수를 (a, b)라고 할 때, (a, b)의 최대 공약수는 (b, r)의 최대 공약수와 같다.

즉, (a, b) = (b, r) 가 성립한다는 뜻이다.

예를 들어, 두 수 1071, 1029 가 있다고 가정해보자.

(1071, 1029) 일 때, r=42이다. 즉, (1071, 1029) = (1029, 42) 이다.
(1029, 42) 일 때, r=21 이고, (1029, 42) = (42, 21) 이다.
(42, 21) 일 때, r=0 이고, (42, 21) = (21, 0) 이다.

나머지가 0이라는 것은 공통된 약수로 나누어 떨어진다는 의미이므로 최대공약수는 7이 된다.

즉, (1071, 1029) = (1029, 42) = (42, 21) = (21, 0) = 21 처럼 쓸 수 있다.

그리고 GCD(A, B) = d 라고 한다면 A와 B는 각각 다음과 같이 나타낼 수 있다.

이를 알고리즘으로 구성하자면 다음과 같다.

  • While 반복문 방식 - 시간 복잡도 O(n)
    int gcd(int a, int b) {
      int mod = a % b;
      while(mod > 0) {
          a = b;
          b = mod;
          mod = a % b;
      }
    }
    
  • 재귀 방식 - 시간 복잡도 O(logN)
    int gcd(int a, int b) {
      if (a % b == 0)
          return b;
      } else {
          return gcd(b, a % b);
      }
    }
    

최소 공배수를 구하는 방법은 더 간결하다.
두 수 a와 b의 최소공배수는 a와 b의 곱을 a와 b의 최대공약수를 나눈 것과 같다.

즉, 아래와 같이 알고리즘을 구성할 수 있다.

  • 최소공배수
    int lcm(int a, int b) {
      return (a * b) / gcd(a, b);
    }
    

내가 작성한 코드

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] str = br.readLine().split(" ");
        int a = Integer.parseInt(str[0]);
        int b = Integer.parseInt(str[1]);
        
        System.out.println(gcd(a, b));
        System.out.println(lcm(a, b));
    }
    
    // 최대공약수
    private static int gcd(int a, int b) {
        int mod = a % b;
        while (mod > 0) {
            a = b;
            b = mod;
            mod = a % b;
        }
        return b;
    }
    
    // 최소공배수
    private static int lcm(int a, int b) {
        return (a * b) / gcd(a, b);
    }
}

reference

더 많은 알고리즘 문제 풀이는 여기서 확인할 수 있다.

댓글남기기