; Returns the the given sequence with the given item appended to it.
(defn snoc [xs x] (concat xs [x]))
; Returns the Fibonacci sequence up to the highest number less than max.
(defn fib [max]
(loop [a 1, b 1, acc [1]]
(if (> b max)
acc
(recur b (+ a b) (snoc acc b)))))
; Project Euler Problem 2: Attempt A
(defn pe2a []
(reduce +
(filter even? (fib 4000000))))
作为参考:
Fibonacci
序列中的每个新术语都是通过将
前两个术语相加而生成的。以1
和2开头,前10个项将是:
1、2、3、5、8、13、21、34、55、89,...
通过考虑
值不超过
的斐波那契数列中的项
,求和
偶值项的总和。
#1 楼
(defn snoc [xs x] (concat xs [x]))
有一个原因在clojure中没有默认定义
snoc
:由于在单链表的末尾附加需要O(n)的时间,因此这实际上很昂贵。使用功能语言递归地构建非惰性列表时,通常会以错误的方式构建列表(使用cons
而不是snoc
),然后在最后将其反转以避免这种开销。但是在这种情况下,实际上有一个更好的方法:通过使用惰性序列而不是严格的列表,我们可以避免需要
loop
/ recur
并节省构建列表的成本。我们还可以通过先创建一个包含所有斐波那契数字的惰性序列,然后使用take-while
接受小于给定最大值的延迟序列,来将创建斐波那契数字的逻辑与决定所需数量的逻辑分开。这将导致以下代码:;; A lazy sequence containing all fibonacci numbers
(def fibs
(letfn
[(fibsrec [a b]
(lazy-seq (cons a (fibsrec b (+ a b)))))]
(fibsrec 1 1)))
;; A function which returns all fibonacci numbers which are less than max
(defn fibs-until [max]
(take-while #(<= % max) fibs))
评论
\ $ \ begingroup \ $
我想我已经很好地分解了您的代码。可以肯定的是,%的作用是什么?据我所知,它代表隐式传递给匿名函数的参数。
\ $ \ endgroup \ $
–杰里米·海勒(Jeremy Heiler)
2011年1月27日20:12
\ $ \ begingroup \ $
@Jeremy:是的。 #(<=%max)只是写(fn [x](<= x max))的一种简短方法,即,一个函数接受一个参数,然后检查该参数是否小于或等于max。
\ $ \ endgroup \ $
–sepp2k
2011年1月27日20:18
#2 楼
我不确定这是否属于此处的注释,但我也使用clojure构建了解决方案。斐波那契数是按照Halloway的“ Clojure编程” p中的无穷序列生成的。 136.然后,我使用列表推导进行求和;;Programming in Clojure p. 136
(defn fibo [] (map first (iterate (fn [[a b]] [b (+ a b)]) [0 1])))
(defn proj-euler2 []
(reduce + (for [x (fibo) :when (even? x) :while (< x 4000000)] x)))
#3 楼
而不是编写snoc,只需使用conj。(conj [1 2] 3)
返回
[1 2 3]
请注意,这仅适用于向量。
(conj (list 1 2) 3)
返回
(3 1 2)
最后,如果涉及性能,则可以使用瞬态向量并将其保留在最后可能的时刻。
PS我喜欢戴夫的解决方案。
评论
您可以直接生成偶数项,而不是生成所有项并丢弃奇数项。直接方法花费更少的时间来生成多达400万个序列。