clojure中的最大子阵列算法

时间:2013-12-26 18:44:24

标签: clojure

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中实现此算法

2 个答案:

答案 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在整个循环执行过程中保持loophere未装箱的能力将在性能方面产生足够的差异。

为了对此进行基准测试,我生成了一个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

有些人可能会觉得这更容易理解,有些人则更喜欢缩小或制作地图。