1000보다 작은 자연수 중에서 3 또는 5의 배수를 모두 더하면?
프로젝트 오일러 문제 중 가장 쉬운 문제일 것이다. 처음에는 문제가 이렇게 쉽지만 뒤로 갈수록 조금씩 어려워져 나중에는 문제가 무슨 뜻인지 이해하기도 힘들어진다. 이 문제는 너무 단순해 아무렇게나 풀어도 답을 구할 수 있다.
방법 1
1부터 1000까지 루프를 돌리면서 3 또는 5의 배수만 더하면 된다. Clojure로는 다음과 같이 짤 수 있다.
(defn using-brute-force [n]
(->> (range 1 n)
(filter #(or (= 0 (mod % 3) (mod % 5))))
(apply +)))
대부분의 사람들이 이렇게 풀었다.
방법 2
1부터 n까지 자연수의 합 을 구하는 공식은 다음과 같다.
이하 의 배수의 합을 이라 하면, 다음과 같이 구할 수 있다.
3의 배수의 합과 5의 배수의 합을 더하면 15의 배수의 합이 두 번 더해진다. 따라서 답을 구하려면 다음과 같이 3의 배수의 합과 5의 배수의 합을 구한 다음 15의 배수의 합을 빼주면 된다.
(defn s
([n] (/ (* n (+ n 1)) 2))
([n m] (* m (s (quot n m)))))
(defn using-formula [n]
(let [n (dec n)]
(-> (s n 3) (+ (s n 5)) (- (s n 15)))))
정리
두 방식의 결과는 다음과 같다.
p001=> (time (using-brute-force 1000)) "Elapsed time: 0.743249 msecs" 233??? p001=> (time (using-forumla 1000)) "Elapsed time: 0.046294 msecs" 233???
int
, long
표현 가능 범위와 관련된 문제는 잠깐 접어두고, 숫자가 커짐에 따라 각 접근법이 어떻게 달라질지 생각해보자. 무식한 방법을 사용할 경우의 복잡도는 이다. 요즘 같이 컴퓨터 속도가 빠른 세상에 단순한 계산은 루프를 1,000이 아니라 1,000,000까지 돌려도 순식간에 답을 얻을 수 있다. 그러나 숫자가 커질수록 속도가 느려질 것이다. 공식을 이용할 경우의 복잡도는 으로, n 크기에 상관 없이 바로 답을 얻을 수 있다.