리트코드 문제를 풀다보면 cyclic list 문제를 더러 만난다. 이 문제도 마찬가지.
먼저 문제를 보자.
prime number 수열을 계산하는 에라토스테네스의 체(sieve)와 비슷한 문제다. 이미 계산된 ugly number에 다시 2를 곱하고, 3을 곱하고, 5를 곱해서 뒤에 나오는 ugly number가 구해진다.
맨 앞에 1이 있고, 여기에 2,3,5를 각각 곱하여 2,3,5가 구해진다.
1 -> 2,3,5
그 다음 ugly number는 2가되고, 2에 다시 2,3,5를 곱하면 4,6,10이 되는데, 이미 구했던 3이 더 작으니 3이 그 다음 ugly number가 된다.
1,2 -> 3,5 4,6,10
1,2,3 -> 5 4,6,10 6,9,15
1,2,3,4 -> 5 6,10 6,9,15 8,12,20
1,2,3,4,5 -> 6,10 6,9,15 8,12,20 10,15,25
이렇게 ugly number가 하나씩 결정될 때마다 그 뒤에 이어질 ugly number들을 계산할 수 있다.
이런 문제는 Haskell의 cyclic list로 풀면 딱이다.
ugly = 1 : merge (map (2*) ugly) (map (3*) ugly) (map (5*) ugly)
여기서 merge는 각 리스트에서 최소값을 꺼내고, 그 값을 뺀 나머지에 대해 같은 과정을 반복한다.
merge as bs cs =
let next = minimum (map head [as,bs,cs])
in next : merge (skip next as) (skip next bs) (skip next cs)
skip x (a:as) = if x == a then as else (a:as)
-- UPDATE
하스켈 같은 취미 언어는 금새 까먹는다. 2년 전에 이미 풀어본 거다. 그런데 이전에 푼 게 더 낫네. ㅠ.ㅠ
먼저 문제를 보자.
2,3,5만을 소인수(prime factor)로 가지는 수를 ugly number라고 했을때 n번째 ugly number를 구하라!
prime number 수열을 계산하는 에라토스테네스의 체(sieve)와 비슷한 문제다. 이미 계산된 ugly number에 다시 2를 곱하고, 3을 곱하고, 5를 곱해서 뒤에 나오는 ugly number가 구해진다.
맨 앞에 1이 있고, 여기에 2,3,5를 각각 곱하여 2,3,5가 구해진다.
1 -> 2,3,5
그 다음 ugly number는 2가되고, 2에 다시 2,3,5를 곱하면 4,6,10이 되는데, 이미 구했던 3이 더 작으니 3이 그 다음 ugly number가 된다.
1,2 -> 3,5 4,6,10
1,2,3 -> 5 4,6,10 6,9,15
1,2,3,4 -> 5 6,10 6,9,15 8,12,20
1,2,3,4,5 -> 6,10 6,9,15 8,12,20 10,15,25
이렇게 ugly number가 하나씩 결정될 때마다 그 뒤에 이어질 ugly number들을 계산할 수 있다.
이런 문제는 Haskell의 cyclic list로 풀면 딱이다.
ugly = 1 : merge (map (2*) ugly) (map (3*) ugly) (map (5*) ugly)
여기서 merge는 각 리스트에서 최소값을 꺼내고, 그 값을 뺀 나머지에 대해 같은 과정을 반복한다.
merge as bs cs =
let next = minimum (map head [as,bs,cs])
in next : merge (skip next as) (skip next bs) (skip next cs)
skip x (a:as) = if x == a then as else (a:as)
-- UPDATE
하스켈 같은 취미 언어는 금새 까먹는다. 2년 전에 이미 풀어본 거다. 그런데 이전에 푼 게 더 낫네. ㅠ.ㅠ