[TIL 18th] 재귀 & 유클리드 호제법 다시 사용해보기
by 노실언니[문제1] 프로그래머스 최대공배수, 최소공약수 구하기
(링크)
"어떻게 저 사람들은 재귀를 딱딱 떠올릴수있지?"
재귀라는 개념은 대학교 1학년때 컴공에 대한 만족도를 하드하게 만들었던 개념 중에 하나이다.
유클리드 호제법(Euclidean Algorithm)은 두 자연수의 최대공약수(Greatest Common Divisior)를 구하는 방식 중 하나이다.
해당 방식의 특징은 재귀방식을 사용했다는 점이고, 최악의 경우에도 시간 복잡도가 O(log(min(A,B)))로 작동한다는 장점이 있다.
최대공배수(LCM)는 두 수의 곱을 GCD로 나누면 구할 수 있다.
유클리드 호제법의 원리는 아래와 같다.
1) A>B인 두 수의 최대공약수를 G라 한다면 (G = GCD(A, B)) → A=𝛼×G, B=𝛽×G (𝛼, 𝛽는 서로소) 라고 할 수 있다.
2) A를 B로 나눌 때의 식을 쓰면 → A = 몫qB + 나머지r 로 표현할 수 있다.
3) 식2)에 식1)을 대입하면 → 𝛼×G = q(𝛽×G) + r 이다.
4) 나머지r을 좌변에 두어 식을 정리하면 → r = 𝛼×G - q(𝛽×G) = (𝛼 - q𝛽)×G = dG (d = 𝛼 - q𝛽)이다.
5) 식3)에 식4)를 대입하면 → 𝛼×G = q(𝛽×G) + dG (d = 𝛼 - q𝛽)
6) 식5)를 G로 나누면 → 𝛼 = q𝛽 + d (d = 𝛼 - q𝛽)
7) 식6)의 𝛽 와 d 의 최대공약수 G' 가 1을 초과한다고 가정한다. GCD(𝛽,d) = G' > 1, 𝛽=𝛽'×G', d=d'×G'
8) 식2)에 식7)을 대입하면 𝛼 = q𝛽 + d = q(𝛽'×G') + d'×G' = (q𝛽'+d')×G' 이다.
9) 𝛼, 𝛽는 서로소인데(1) 𝛽 와 d 의 최대공약수 G' 가 1을 초과한다고 가정하면 𝛼 = (q𝛽'+d')×G' 𝛽=𝛽'×G' 이 되어 모순이 생긴다.
10) 따라서, 𝛽 와 d 의 최대공약수는 1이다.
11) G𝛽 와 Gd 즉 B와 r의 최대공약수는 G이다. GCD(B, r) = G
12) [재귀] GCD(A, B) = GCD(B, r) = GCD(r, B%r) = ・・・ = G 로 간단하게 바꿀 수 있다.
13) [재귀의 종료조건] 식12) 에서 필연적으로 GCD(X,G)의 상황이 만들어진다. (X = q'G + 0)
GCD(A, B) = GCD(B, r) 의 규칙대로라면 GCD(X,G) = GCD(G,0)이다.
따라서, 두번째 인자가 0이 될 때의 첫번째 인자가 최대공약수이다.
GCD(A, B) = GCD(B, A%B) = GCD(G, 0) = G
[답1] C++ 재귀함수로 구현한 코드
#include <vector>
using namespace std;
int GCD(int a, int b){
if(b == 0) return a; // 재귀 탈출
return GCD(b, a%b); // 재귀
}
int LCM(int a, int b, int gcd){
return (a*b/gcd);
}
vector<int> solution(int n, int m) {
if(n<m) {
int temp=n;
n=m;
m=temp;
}
int gcd = GCD(n,m);
int lcm = LCM(n,m,gcd);
vector<int> answer;
answer.push_back(gcd);
answer.push_back(lcm);
return answer;
}
[답2] 조금 더 간결한 코드
#include <vector>
using namespace std;
int gcd(int a, int b){
return (b ? gcd(b, a%b) : a); // 재귀
}
vector<int> solution(int n, int m) {
vector<int> answer;
if(n<m) {
int temp=n;
n=m;
m=temp;
}
answer.push_back(gcd(n,m));
answer.push_back(n*m/answer[0]);
return answer;
}
[답3] 라이브러리 활용
#include <vector>
using namespace std;
int gcd(int a, int b){
return (b ? gcd(b, a%b) : a); // 재귀
}
vector<int> solution(int n, int m) {
vector<int> answer;
if(n<m) {
int temp=n;
n=m;
m=temp;
}
answer.push_back(gcd(n,m));
answer.push_back(n*m/answer[0]);
return answer;
}
'Today I Learned' 카테고리의 다른 글
1월 1, 2주차 우수 TIL에 선정되다 (예? 제가요?) (0) | 2025.01.23 |
---|---|
[TIL 19th] 벡터의 주소를 가리키는 포인터를 사용하면 낭패본다 (0) | 2025.01.20 |
[TIL 17th] exist에 대한 공부를 하다, 생각보다 어려운 친구였군 (0) | 2025.01.16 |
[TIL 16th] MySQL 문자열 속에 무언가를 삽입/대체하는 함수 (0) | 2025.01.15 |
[TIL 15th] 객체지향 철학에 대한 책을 샀다 (0) | 2025.01.14 |
블로그의 정보
노력하는 실버티어
노실언니