Project Euler Problem 33 asks us to find a particular pattern of fraction which satisfies several characteristics:
- It is less than one.
- It has two digits in both numerator and denominator.
- You can simplify the fraction correctly by canceling a single digit from both numerator and denominator.
- It is not a trivial fraction like (30/50).
My first attempt had the right idea, but the implementation has flaws because I tried to manage the numerator and denominator separately.
(defn as-digits [num]
(map #(Character/getNumericValue %) (str num)))
(defn gcd [a b] (if (zero? b) a (recur b (mod a b))))
(defn lcm [a b] (/ (* a b) (gcd a b)))
(defn curious-frac? [num den]
(let [n (as-digits num)
d (as-digits den)]
(and (= (second n) (first d))
(not (zero? (first n)))
(not (zero? (second d)))
(= (/ (first n) (second d))
(/ num den))
(< (/ num den) 1))))
(defn reduce-fraction [[n d]]
(let [g (gcd n d)]
[(/ n g) (/ d g)]))
(defn euler-33 []
(let [fracs (for [num (range 10 100)
den (range num 100)
:when (curious-frac? num den)]
[num den])]
(reduce-fraction [(reduce * (map first fracs))
(reduce * (map second fracs))])))
(time (euler-33))
Compare this to bibi’s nice solution from clojure-euler:
(defn non-trivial?[n d]
(let [x (quot n 10)
y (rem n 10)
u (quot d 10)
v (rem d 10)]
(cond
(zero? v) false
(and (= y u) (= (/ x v) (/ n d))) true
:else false)))
(defn euler-33-bibi []
(let [fracs (for [n (range 10 99)
d (range (inc n) 100)
:when (non-trivial? n d)]
(/ n d))]
(.denominator (reduce * fracs))))
Lesson learned: don’t ignore the built-in data types like I did! Follow bibi’s example and let clojure manage your fractions automatically for you!