Problem 41 is yet another variation on the theme of pandigitality and primality. If nothing else, it is teaching me how to reuse my own code…
;; from euler-32
(defn all-unique? [digits]
(let [unique (distinct digits)]
(= (count unique) (count digits))))
(defn n-pandigital? [n digits]
(and (nil? (some zero? digits))
(nil? (some #(< n %) digits))
(= n (count digits))
(all-unique? digits)))
;; as-digits is from euler-30
(defn pandigital-prime? [pr]
(let [d (as-digits pr)]
(n-pandigital? (count d) d)))
(defn euler-41 []
(last (filter pandigital-prime?
(take-while #(< % 1000000)
(drop-while #(< % 100000) primes)))))
(time (euler-41)) ;; "Elapsed time: 9591.044968 msecs"
Hmm, performance isn’t bad, especially when the primes are already cached into memory; the speed improves by about 3x. However, we also could try an algorithm that tests for primality instead of pandigitality:
(use '[clojure.contrib.combinatorics :only (permutations)])
;; Use prime? and as-int from problem euler-37
(defn euler-41-alt
([] (euler-41-alt "987654321"))
([s] (first (filter #(prime? (as-int %))
(lazy-cat (permutations s)
[(euler-41-alt (rest s))])))))
(time (euler-41-alt)) ;; "Elapsed time: 1866.518849 msecs"
I guess it’s cheaper to check generate pandigital permutations and check primality than to generate primes and check pandigitality.