2023-03-24 TIL (2)

0v0baek·2023년 3월 24일
0

TIL

목록 보기
13/92

분수의 덧셈

첫 번째 분수의 분자와 분모를 뜻하는 numer1, denom1, 두 번째 분수의 분자와 분모를 뜻하는 numer2, denom2가 매개변수로 주어집니다. 두 분수를 더한 값을 기약 분수로 나타냈을 때 분자와 분모를 순서대로 담은 배열을 return 하도록 solution 함수를 완성해보세요.

문제는 이거다.
그니까 두 분수를 더한 뒤 기약 분수로 만들어서 각 값의 분자, 분모를 리스트로 return 하라는 소리다.
처음에 봤을 때 아 이거 최소공배수 최대공약수 활용하면 되겠는데. 하고 코드를 먼저 짜봤다.

1번 방법

첫 번째 값은 처음부터 분수를 소수로 바꿔서 더한 다음에
그 소수에 100을 곱한 값을 분자로,
100을 분모로 해서
두 값의 최대 공약수를 구한 뒤 최대 공약수로 나눠보려고 했다.

numer1 = 1
denom1 = 2
numer2 = 3
denom2 = 4

value_numer = 100 * (numer1 / denom1 + numer2 / denom2)
value_denom = 100

print(value_denom)


def GCD(a, b):
    while (b):
        a, b = b, a % b
        return a


print(GCD(value_denom, value_numer))

유클리드를 활용해서 구현해보려고 시도하다가 중간에 어? 이거 아닌데 싶어서 그만둬서 코드는 미완성이다. 미완성이지만 기록을 위해 남겨 둠
그만 둔 이유 : 나눈 값이 소숫점 3자리 이상이 되면 100을 곱해봤자 정수가 안 되잖아!!

2번 방법

받은 분모 값의 최소 공배수를 구한 뒤,
분자끼리는 분모를 최대 공배수로 만들 때 곱한 값을 곱해 더해주고
분모는 최소 공배수를 return 해주는 쪽이 훨씬 간단할 것 같았다.
만약 분자와 분모가 서로소(최대 공약수가 1)가 아닐 경우엔 최대 공약수로 나눠주면 될 것 같았다.

그 과정에서 최대 공배수를 간단하게 구해주는 python 내장 함수 math를 활용해보기로 했다.

# math import
import math


def solution(numer1, denom1, numer2, denom2):
    # math 함수를 이용해 분모의 최소 공배수를 구해준다
    lcm = math.lcm(denom1, denom2)
	
    # 만약 분모 값이 분모의 최소 공배수와 일치하지 않을 경우
    if denom1 != lcm:
        num1 = int(numer1 * (lcm / denom1))
    # 분모 값이 최소 공배수와 일치할 경우
    else:
        num1 = numer1
	
    # 두 번째 값도 똑같이 실행해줌
    if denom2 != lcm:
        num2 = int(numer2 * (lcm / denom2))
    else:
        num2 = numer2
	
    # 최종 값 분자와 분모의 최대 공약수를 구함
    gcd = math.gcd(num1+num2, lcm)
	
    # 최대 공약수가 1일 경우 (분자와 분모가 서로소일 경우)
    if gcd == 1:
        return num1 + num2, lcm
    # 최대 공약수가 1아 아닐 경우 (분자와 분모가 서로소가 아닐 경우).
    # 나눗셈을 하기 때문에 소숫점을 떼기 위해서 int 연산자를 사용했다.
    else:
        return int((num1 + num2) / gcd), int(lcm / gcd)
    

# vscode에서 테스트 해볼려고 추가한 부분. programmers에서는 지워도 됨
value = solution(1, 2, 3, 4)
print(value)

>>> [5, 4]

vscode는 잘 작동했다!!
그럼 이걸 programmers에 넣어보자!! 했는데..... 구동 안 됨.

맙소사...
math는 python 3.9부터 적용되는데, programmers는 3.8.5라 math 내장 함수 사용이 안 된다...

그럼 math가 아닌 최소 공배수랑 최대 공약수 구하는 방법을 찾아야 할 것 같다.

3번 방법

이번엔 math를 사용하지 않는 방법으로 최소 공배수랑 최대 공약수를 구해봐야 할 것 같다.
최소 공배수 최대 공약수는 한참 붙잡고 있다가 그냥 구글의 힘을 빌려서 찾았다. 최대 공약수는 예상대로 유클리드 호제법을 사용하는 게 정석.

다른 부분은 2번 방법의 코드와 같아서, 최소 공배수랑 최대 공약수 부분의 코드만 붙여넣기.

최소 공배수(lcm)

def lcm(a, b):
	for lcm in range(max(a, b), (a * b) + 1):
		if lcm % a == 0 and lcm % b == 0:
			return lcm

for문의 range를 이용해서 최소 공배수를 구해준다.

두 수 중 더 큰 수부터 시작해서 두 수의 곱 + 1 (두수의 곱이 최소 공배수일수도 있기 때문) 에 도달할 때 까지 for문을 돌려준다.

최대 공약수(gcd)

def gcd(a, b):
	for gcd in range(min(a, b), 0, -1):
		if a % gcd == 0 and b % gcd == 0:
			return gcd

최대 공약수는 최소 공배수를 구했던 것과 반대로 하면 된다.
다만, 이번엔 숫자를 1씩 줄여가야 하기 때문에 세 번째 인수에 꼭 -1을 넣어준다.

두 수 중 더 작은 수부터 시작해서 0에 도달할 때 까지 for문을 돌려준다.

다른 사람의 풀이

배신감이 든다...
분명 math가 안된다고 해서 최소공배수 최대공약수 구하는 걸 다시 공부했는데
다른 사람들 풀이를 보니까 math가 사용된다!!!!!!!!!!!!!!! 저기요 !!!!!!

그리고 내 방식보다 훨씬 더 간단하게 해결한 사람들이 있어서 그걸 들고와서 공부해봤다.

import math

def solution(denum1, num1, denum2, num2):
    denum = denum1 * num2 + denum2 * num1
    num = num1 * num2
    gcd = math.gcd(denum, num)
    return [denum//gcd, num//gcd]

갑자기 너무 수학이라서 손으로 쓰면서 이해하려고 해봤다.

이해했다 !!
간단하게 생각하면 된다.

분수 a와 분수 b가 있다면
분수 a의 분자 분모에 분수 b의 분모를 곱해주고,
분수 b의 분자 분모에 분수 a의 분모를 곱해준다.

그러니까 어짜피 나중에 최대공약수로 나눠줄거면, 처음에 최소공배수로 나눠주는 짓을 안해도 되는거다!!!

# 분자의 합 = 분수 1의 분자 * 분수 2의 분모 + 분수 2의 분자 * 분수 1의 분모
denum = denum1 * num2 + denum2 * num1

분수 a의 분모에 분수 b의 분모를 곱하는거나
분수 b의 분모에 분수 a의 분모를 곱하는거나
똑 같 은 말이기 때문에, 그냥 단순하게 분수 a,b의 분모끼리 곱해준다.

# 통분된 분모 = 분수 1의 분모 * 분수 2의 분모
num = num1 * num2

이제, 나온 분자와 분모의 최대공약수를 구해 그걸로 나눠주면 된다.

# math 연산자를 사용해서 최대공약수(gcd)를 구해주자.
gcd = math.gcd(denum, num)
# 약분한 값을 return (//를 사용하면 int를 쓰지 않아도 몫이 정수로 떨어진다.)
return [denum//gcd, num//gcd]

코딩 공부를 하면 할 수록 느끼지만 정말 코딩은 아이디어 싸움.. 이라는 생각이 든다.
누가 더 기발하고 간단하게 문제를 해결할 수 있는지가 코드가 100줄이 되느냐 5줄이 되느냐의 차이같다. 더 열심히 공부하자!!

profile
개발 공부 하는 비전공자 새내기. 꾸준히 합시다!

0개의 댓글