kanade的算法解决了maximum subarray problem。我正在尝试学习clojure,所以我想出了这个实现:
(defn max-subarray [xs]
(last
(reduce
(fn [[here sofar] x]
(let [new-here (max 0 (+ here x))]
[new-here (max new-here sofar)]))
[0 0]
xs)))
这看起来真的很冗长。 是否有更简洁的方法在clojure中实现此算法?
答案 0 :(得分:2)
正如我在对该问题的评论中所说,我认为OP的方法是最佳的。这给出了一个完全普遍的问题,其中输入是可选的任意数字。
但是,如果添加的要求是输入应该是long的集合(或双精度;其他原语也可以,只要我们不将整数与浮点数混合),{{1}通过利用原始算法可以使基于/ loop
的解决方案明显更快:
recur
这实际上是我的眼睛可读,但我更喜欢(defn max-subarray-prim [xs]
(loop [xs (seq xs) here 0 so-far 0]
(if xs
(let [x (long (first xs))
new-here (max 0 (+ here x))]
(recur (next xs) new-here (max new-here so-far)))
so-far)))
,没有特别的理由使用reduce
/ loop
。现在的希望是recur
在整个循环执行过程中保持loop
和here
未装箱的能力将在性能方面产生足够的差异。
为了对此进行基准测试,我生成了一个100000个随机整数的向量,范围为-50000,...,49999:
so-far
完整性检查((def xs (vec (repeatedly 100000 #(- (rand-int 100000) 50000))))
是指OP的实施):
max-subarray-orig
Criterium基准:
(= (max-subarray-orig xs) (max-subarray-prim xs))
;= true
这是每次通话从~5.29 ms跳到~2.12 ms。
答案 1 :(得分:1)
这里使用循环并重复更接近地模仿维基百科页面中的示例。
user> (defn max-subarray [xs]
(loop [here 0 sofar 0 ar xs]
(if (not (empty? ar))
(let [x (first ar) new-here (max 0 (+ here x))]
(recur new-here (max new-here sofar) (rest ar)))
sofar)))
#'user/max-subarray
user> (max-subarray [0 -1 1 2 -4 3])
3
有些人可能会觉得这更容易理解,有些人则更喜欢缩小或制作地图。