1~20까지 모두 나누어떨어지는 가장 작은수, 즉 공통의 배수, 최소공배수를 구하는 문제입니다.
Smallest multiple
2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
최소공배수는 두수를 곱해서 최대공약수로 나누어 주면 됩니다. 여러숫자의 최소공배수일때는 두수씩 순차적으로 계산해주면 최종나오는 최소공배수가 전체수의 최소공배수가 됩니다.
그러면 먼저 최대공약수(gcd)를 먼저 구해야 되겠네요.(최소공배수:lcm)
방법 1
최대공약수로 계산
def get_gcd(num1,num2): i=1 while i <= num2: if num1%i==0 and num2%i==0: gcd=i i+=1 return gcd print(get_gcd(12,18)) print(get_gcd(27,63))
6 9
가장 기본적인 방법입니다. 두수중 작은수를 기준으로 1부터 작은수까지 루프를 돌면서, 두수를 동시에 다 나누어 보고, 나누어 떨어지면 공약수이고, 마지막 공약수가 최대공약수가 되겠습니다.
또는 math 모듈의 gcd() 함수 이용
import math math.gcd(12,18)
math 모듈을 이용할때는 gcd()함수로 정수형이 들어가는지 확인해야 합니다. 나눗셈의 결과로 float 형이 생성되기 때문에, int()함수로 정수형숫자로 바꿔줘야 합니다.
import math lcm=1 for i in range(1,21): gcd = math.gcd(lcm,i) lcm = int(lcm*i/gcd) print(i,lcm)
방법 2
프로젝트 오일러 포럼에 있는 다른유저가 만든 코드인데, 몇가지 생소한 문법이 있어서 가져와봤습니다.
from functools import reduce n = reduce(lambda x, y: x*y, range(2,21)) #1~20까지 다 곱하기 print(n) for i in range(20,1,-1): print(i,n,n/i) if all(not n/i%j for j in range(2,21)): #1~20까지 다 나누어 떨어지면 n = n//i #원래수를 나누어서 크기를 줄임. print(i,n) print(n)
1~20까지 먼저 다 곱해놓고, 거꾸로 나눠가면서, 1~20까지 나누어봐서 한꺼번에 나누어 떨어지면 크기를 줄여나갑니다. 3번문제에서 썼었던 brute force 방법이라고 할수 있겠네요.
reduce() 함수
https://www.python-course.eu/python3_lambda.php
>>> import functools >>> functools.reduce(lambda x,y: x+y, [47,11,42,13]) 113 >>>
reduce()함수는 순차적으로 계산을 해 나가는 함수입니다. lambda 로 정의된 어떠한 연산을 앞에서부터 두번째 매개변수인 어떤 범위에 대해서 순서대로 계산해서 최종 결과를 return 하는 함수입니다. 이 경우엔, 전체수를 합하는 연산과 같네요.
lambda operation
lambda x,y: x+y, [47,11,42,13]
람다 함수는 함수안에 작은 함수라고 보시면 될거 같네요. javascript를 공부하신 분은 Arrow function( () => {} ) 을 떠올리시면 될것 같습니다. 완전히 같진 않지만요. 콜론(:)앞쪽 x,y를 넘겨줘서, 콜론 뒤의 x+y 의 연산을 수행해서 리턴하라는 의미입니다.
if all():
all() 안의 조건이 "모두" 참인지를 판단합니다. 하나라도 참이 아니면 False를 반환합니다.
예를 들어, 10 이 2와 5로 동시에 나누어 떨어지는지를 알고 싶으면,
if all(10%i == 0 for i in [2,5]): print('yes')
yes
또는
if all(not 10%i for i in [2,5]): print('yes')
두 번째 코드는 나머지 연산(10%i)자체를 논리연산자를 대신해 사용한것입니다. 나누어 떨어지면 값이 0(논리값 False)이 되어서 if문이 조건을 만족하지 않는것으로 판단하기 때문에, not을 붙여주면 반대로 true가 되어서, 원하는 동작이 실행됩니다.
if not all():
not을 all()앞쪽에 붙여주면, 논리적 반대값이 아니라, all 의 부정, 즉 "모두 참이 아닐때"를 의미합니다. 즉 하나라도 거짓(혹은 0)이 있으면, 참이 되어서 그다음 문장을 실행합니다. 햇갈릴테니 직접 한번 해보세요.