project-euler1〜20

clojureで書くことに慣れるために簡単な問題を解いてみる。

my.math.prime

自分用の個人的なライブラリはどのあたりに置くのが良いのだろう(今は~/mylib/clojure以下に置いている)

(ns my.math.prime
  (:use clojure.contrib.math))

(defn prime? [n]
  (let [sqn (int (sqrt n))]
    (or (= 2 n)
	(and (odd? n)
	     (loop [i 3]
	       (cond (> i sqn) true
		     (zero? (rem n i)) false
		     :else (recur (+ i 2))))))))


(def prime-seq
     (let [seq ((fn step [n]
		  (lazy-seq
		   (if (prime? n) (cons n (step (+ 2 n))) (step (+ 2 n)))))
		3)]
     (lazy-cat [2] seq)))

(defn- divide-even [n]
  (loop [r 1, n n]
    (if (even? n)
      (recur (* r 2) (bit-shift-right n 1))
      [r n])))

(defn prime-factors [n]
  (let [[r n*] (divide-even n)
	rs (if (= 1 r) '() (list r))]
    (loop [rs rs, n n*, i 3]
      (cond (= n 1) (cons n rs)
	    (zero? (rem n i)) (recur (cons i rs) (/ n i) i)
	    :else (recur rs n (+ i 2))))))

1.clj

http://projecteuler.net/index.php?section=problems&id=1

(def dividable? (comp zero? rem))

(reduce (fn [n x] (if (or (dividable? x 3) (dividable? x 5)) (+ x n) n))
	0 (range 1 1000)) ; => 233168

2.clj

http://projecteuler.net/index.php?section=problems&id=2

(use '[clojure.contrib.seq-utils :only (rec-cat)])
(use '[clojure.contrib.math :only (expt)])

(let [n (* 4 (expt 10 6))]
  (->> (rec-cat s [0 1] (map + s (rest s)))
       (take-while #(< % n))
       (filter even?)
       (reduce +))) ; => 4613732

3.clj

http://projecteuler.net/index.php?section=problems&id=3

(use my.math.prime)
(apply max (prime-factor 13195)) ; => 29
(apply max (prime-factor 600851475143)) ; => 6857

4.clj

http://projecteuler.net/index.php?section=problems&id=4

(defn palindrome? [n]
  (let [s (str n)]
    (= s (apply str (reverse s)))))

(defn solve [from to]
  (let [xs (for [i (range from to)
		 j (range i to)
		 :when (palindrome? (* i j))]
	     (* i j))]
    (apply max xs)))
  
(solve 100 1000) ; => 906609

5.clj

http://projecteuler.net/index.php?section=problems&id=5

(use '[clojure.contrib.math :only (lcm)])
(reduce lcm (range 1 10)) ; => 2520
(reduce lcm (range 1 20)) ; => 232792560

6.clj

http://projecteuler.net/index.php?section=problems&id=6

(let [sq #(* %1 %1), n 101]
  (- (sq (reduce + (range 1 n)))
     (->> (range 1 n)
	  (map sq)
	  (reduce +)))) ; => 25164150

7.clj

http://projecteuler.net/index.php?section=problems&id=7

(use my.math.prime)
(nth prime-seq (- 6 1)) ; => 13
(nth prime-seq (- 10001 1)) ; => 104743

8.clj

http://projecteuler.net/index.php?section=problems&id=8

(use '[clojure.contrib.duck-streams :only (reader)])

(binding [*in* (reader "8.dat")]
  (->> (str (read-line))
       (partition 5 1)
       (map (comp (partial reduce *) 
		  (partial map #(- (int %) 48))))
       (apply max))) ; => 40824

9.clj

http://projecteuler.net/index.php?section=problems&id=9

(defn solve [n]
  (let [sq #(* %1 %1)]
    (loop []
      (let [a (rand-int n)
	    b (rand-int (- n a))
	    c (- n a b)
	    [a* b* c*] (apply vector (sort > (list a b c)))]
	(if (= (sq a*) (+ (sq b*) (sq c*)))
	  (* a* b* c*)
	  (recur))))))

(solve 1000) ; => 31875000

10.clj

http://projecteuler.net/index.php?section=problems&id=10

(use my.math.prime)
(reduce + (take-while #(< % 2000000) prime-seq)) ; => 142913828922

11.clj

http://projecteuler.net/index.php?section=problems&id=11

(use '[clojure.contrib.duck-streams :only (read-lines)])
(use '[clojure.contrib.str-utils :only (re-split)])
(use '[clojure.contrib.seq-utils :only (indexed)])

(def map-to-vector (comp (partial apply vector) map))
(defn read-data [file]
  (map-to-vector (fn [line] 
		   (map-to-vector #(Integer/parseInt %) (re-split #"\s" line))) 
		 (read-lines file)))

(defn transpose [xs] (apply map list xs))
(def horizontals (partial mapcat #(partition 4 1 %))) 
(def verticals (comp horizontals transpose))

(defn- gen$ [yfn xfn]
  #(take 4 (iterate (fn [p] [(yfn (p 0)) (xfn (p 1))]) %)))
(defn- mget [m ps] (reduce #(get %1 %2 0) m ps))

(defn diagonally [mat gen]
  (let [h (count mat), w (count (first mat))
	mget* (partial mget mat)]
    (for [i (range 0 h), j (range 0 w)]
      (map mget* (gen [i j])))))

(defn solve [file]
  (let [xs (read-data file)]
    (->> (lazy-cat (horizontals xs)
		   (verticals xs)
		   (diagonally xs (gen$ inc inc))
		   (diagonally xs (gen$ inc dec)))
	 (map (partial reduce *))
	 (apply max))))

(solve file)

12.clj

http://projecteuler.net/index.php?section=problems&id=12

(use '[clojure.contrib.seq-utils :only (reductions)])
(use '[clojure.contrib.math :only (sqrt)])

(defn divisors [n]
  (let [sqn (int (sqrt n))]
    (loop [r (list 1 n), i 2]
      (cond (> i sqn) r
	    (zero? (rem n i)) (let [q (/ n i)]
				(if (= q i) 
				  (recur (cons i r) (inc i))
				  (recur (cons i (cons q r)) (inc i))))
	    :else (recur r (inc i))))))

(def tn-seq (reductions + (iterate inc 1)))

(first 
 (drop-while (fn [i] (> 500 (count (divisors i)))) 
	     tn-seq)) ; => 76576500

13.clj

http://projecteuler.net/index.php?section=problems&id=13

(use '[clojure.contrib.duck-streams :only (read-lines)])
(reduce (fn [n line] (+ n (BigInteger. line)))
	0 (read-lines "13.dat")) ; => 5537376230390876637302048746832985971773659831892672

14.clj

http://projecteuler.net/index.php?section=problems&id=14

(use '[clojure.contrib.math :only (expt)])

(defn f [n]
  (loop [i 0, n n]
    (cond (= 1 n) (inc i)
	  (even? n) (recur (inc i) (bit-shift-right n 1))
	  :else (recur (inc i) (+ (* 3 n) 1)))))

(reduce (fn [[r n] i]
	  (let [n* (f i)]
	    (if (> n* n) [i n*] [r n])))
	[0 0] (range 1 (expt 10 6))) ; => [837799 525]

15.clj

http://projecteuler.net/index.php?section=problems&id=15

(defn fact [n] (reduce * 1 (range 1 n)))
(/ (fact 40) (fact 20) (fact 20)) ; => 1378465288200

16.clj

http://projecteuler.net/index.php?section=problems&id=16

(use '[clojure.contrib.math :only (expt)])
(reduce + (map (comp #(- % 48) int) (str (expt 2 1000)))) ; => 1366

17.clj

http://projecteuler.net/index.php?section=problems&id=17

(defn f [i]
  (condp = i
    0 "", 1 "one",  2 "two", 3 "three", 4 "four", 5 "five", 6 "six", 7 "seven", 8 "eight", 9 "nine"
    10 "ten", 11 "eleven", 12 "twelve", 13 "thirteen", 14 "fourteen", 15 "fifteen", 
    16 "sixteen", 17 "seventeen", 18 "eighteen", 19 "nineteen"))

(defn g [i j]
  (if (<= i 1)
    (f (+ (* i 10) j))
    (str 
     (condp = i
       2 "twenty", 3 "thirty", 4 "forty", 5 "fifty", 6 "sixty", 7 "seventy", 8 "eighty", 9 "ninety")
     (f j))))

(defn h [i j k]
  (if (and (zero? k) (zero? j))
    (str (f i) "hundred")
    (str (f i) "hundred" "and" (g j k))))

(defn dispatch [x]
  (condp = (count x)
    1 (apply f x)
    2 (apply g x)
    3 (apply h x)))

(+ (count "onethousand")
   (->> (range 1 1000)
	(map (comp count dispatch (partial map (comp #(- % 48) int)) str))
	(reduce + 0)))

18.clj

http://projecteuler.net/index.php?section=problems&id=18

(use '[clojure.contrib.duck-streams :only (read-lines)])
(use '[clojure.contrib.str-utils :only (re-split)])

(defn read-data [file]
  (map (fn [line] 
	 (map #(Integer/parseInt %) (re-split #"\s" line)))
       (read-lines file)))

(defn solve [coll]
  (apply max
	 (reduce (fn [acc row]
		     (map max 
			  (map + (next acc) row) 
			  (map + (reverse (next (reverse acc))) row)))
		 (first coll) (next coll))))

(solve (reverse (read-data "18.dat"))) ; => 1074

19.clj

http://projecteuler.net/index.php?section=problems&id=19

(import 'java.util.Calendar)

(defn calendar
  ([#^Calendar cal] (.clone cal)) 
  ([y m d]
     (doto (Calendar/getInstance)
       (. clear) 
       (. set y (dec m) d))))

;;instance作りまくっているけれど良いのかな?
(let [sun (Calendar/SUNDAY)]
  (->> (calendar 1901 1 1)
       (iterate (fn [cal] 
		  (doto (calendar cal)
		    (. add Calendar/MONTH 1))))
       (filter #(= sun (.get % (Calendar/DAY_OF_WEEK))))
       (take-while #(>= 2000 (.get % (Calendar/YEAR))))
       (count)))

20.clj

http://projecteuler.net/index.php?section=problems&id=20

(->> (reduce * (range 1 101))
     (str)
     (map (comp #(- % 48) int))
     (reduce +)) ; => 648