코딩한걸음
728x90
반응형

https://school.programmers.co.kr/learn/courses/30/lessons/12953

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

문제 설명


두 수의 최소공배수(Least Common Multiple)란 
입력된 두 수의 배수 중 공통이 되는 가장 작은 숫자를 의미합니다. 
예를 들어 2와 7의 최소공배수는 14가 됩니다. 
정의를 확장해서, n개의 수의 최소공배수는 n 개의 수들의 배수 중 공통이 되는 가장 작은 숫자가 됩니다. 
n개의 숫자를 담은 배열 arr이 입력되었을 때 이 수들의 최소공배수를 반환하는 함수, solution을 완성해 주세요.


제한 사항


arr은 길이 1이상, 15이하인 배열입니다.
arr의 원소는 100 이하인 자연수입니다.

N개의 수의 최소공배수 = 최대공약수 * a * b * c * ... * n 이므로
N개의 수의 최대공약수를 구하고 arr안의 모든 요소를 곱한 뒤 최대공약수**(n-1)로 나눠주면 될 듯
제한 조건에서 100이하인 자연수니깐 다 나눌 필요없이 100 이하 소수로만 나눠서 최대 공약수 판단하면 될 듯


풀이

 

로직

1 ~ 100까지 소수를 먼저 찾고

> 주어진 arr에서 각 수를 인수분해하고 각 인수가 높은 것만 모아서 곱하면 최소 공배수

> 또는 math의 gcd를 사용해 풀기

 

초기 코드

# 초기 코드
def is_prime(num):
    for i in range(2, int(num**(0.5))+1):
        if not num % i: return False
    return True
    
def solution(arr):
    prime_counts = {}
    for i in range(2,101):
        if is_prime(i): prime_counts[i]=0
    divisor = []
    for num in arr:
        if num == 1: continue
        num_dict = {}
        for prime in prime_counts.keys():
            prime = int(prime)
            while num % prime == 0:
                num_dict[prime] = num_dict.get(prime,0) + 1
                num = num // prime
        divisor.append(num_dict)
    for divisor_dict in divisor:
        for key,value in divisor_dict.items():
            prime_counts[key] = max(prime_counts[key], value)
    answer = 1
    for key, value in prime_counts.items():
        answer *= key**value
    return answer
# 0.18ms

 

초기 코드는 러프하게 짜기때문에 불필요한 로직이나 알기 힘든 변수명들이 보인다.

 

특히 num_dict 에 각 인수의 갯수를 넣고 divisor 에 num_dict를 넣고

다시 for를 돌려서 prime_counts에 넣는부분을 바로 prime_counts에 넣으면 될 듯.

 

1차 수정 : 가독성 및 로직 개선

# 1차 수정 : 가독성 및 로직 개선
def is_prime(num):
    for i in range(2, int(num**(0.5))+1):
        if not num % i: return False
    return True

def solution(arr):
    answer = 1
    primes = [i for i in range(2, 101) if is_prime(i)]
    prime_counts = {prime: 0 for prime in primes}
    for num in arr:
        if num == 1: continue
        for prime in prime_counts.keys():
            if num < prime: break
            count = 0
            while num % prime == 0:
                count += 1
                num = num // prime
            prime_counts[prime] = max(prime_counts[prime], count)
    for key, value in prime_counts.items():
        answer *= key**value
    return answer
# 0.10ms

 

불필요한 for문을 줄이고, for 문을 일찍 끝내기 위해 break를 추가했다.

 

근데 이런 수학적 문제들은 math를 가져오면 쉽게 풀 수 있다.

두 수(x, y)의 최소공배수(Least Common Multiple, LCM)는

두 수를 서로 곱하고 두 수의 최대공약수(Greatest Common Divisor)를 나누면 나온다.

그럼 여러 수의 최소공배수는? 두 수의 LCM을 구하고 그 LCM과 한 수의 LCM을 구하고..를 반복하면 된다.

functools의 reduce를 이용하면 이 과정을 쉽게 할 수 있다.

 

2차 수정 : gcd, reduce를 사용해 풀기

# 2차 수정 : gcd, reduce 사용해 풀기
import math
from functools import reduce
def lcm(x, y):
    return (x * y) // math.gcd(x, y)
def solution(numbers):
    return reduce(lcm, numbers)
# 0.01ms

 

시간도 엄청 단축된다. 근데 항상 고민이 되는 부분이 'import를 해서 문제를 푸는게 맞을까?' 하는 것이다.

될 수 있으면 import 없이 코드를 구현하는게 맞다고 생각하지만,

itertools의 permutations나 combinations 같은건 직접 구현하기 너무 귀찮다..

 

그냥 import 없이 풀고 하고 풀고 두번 풀면 해결 !

 

 

 

728x90
반응형
profile

코딩한걸음

@Joonyeol_Yoon

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!