git.fiddlerwoaroof.com
Raw Blame History
(ns max-subarray
  (:require [clojure.test :refer [deftest is]]))

(defn propagating
  "Transducer that emits the current maximum value, according to cmp"
  [init cmp]
  (fn [rf]
    (let [cur-max (volatile! init)]
      (completing
       (fn [acc nxt]
         (vswap! cur-max cmp nxt)
         (rf acc @cur-max))))))

(defn max-sequence [xs]
  (-> (into [0]
            (comp (propagating 0 (comp #(max 0 %) +)) ;; Maintain the running sum, as long as it's non-zero
                  (propagating 0 max))                ;; Emit the current maximum running sum
            xs)
      peek)) ;; Get the last maximum running sum (peek on vector makes this fast)

(deftest simple
  (is (= (max-sequence  [-2, 1, -3, 4, -1, 2, 1, -5, 4]) 6))
  (is (= (max-sequence  []) 0))
  (is (= (max-sequence  [1 2 3 4]) 10))
  (is (= (max-sequence  [-1 -2 -3 -4]) 0))

  )

(defn collect-runs [eq]
  (let [sentinel (Object.)]
    (fn [rf]
      (let [c-v (atom sentinel)
            current (atom [])]
        (fn
          ([] (rf))
          ([acc] (rf (rf acc @current)))
          ([acc nxt]
           (when (= @c-v sentinel)
             (reset! c-v nxt))
           (let [result (if (eq @c-v nxt)
                          (do (swap! current conj nxt)
                              acc)
                          (let [r (rf acc @current)]
                            (reset! current [nxt])
                            r))]
             (reset! c-v nxt)
             result)))))))

(defn series-sum [n]
  (format "%.2f" (double (apply + (map #(/ 1.0 (doto % prn)) (take n (iterate #(+ % 3.0) 1.0)))))))