Вы можете решить линейное время -О (п), а не O (п * лог к)), как описано 1. http://articles.leetcode.com/sliding-window-maximum/ (легко перейти от найти Макс найти мин) и 2. https://people.cs.uct.ac.za/~ksmith/articles/sliding_window_minimum.html
Подходы требуют очереди с двойным завершением для управления предыдущими значениями, использующими время O (1) для большинства операций с очередями (то есть push/pop/peek и т. Д.), А не O (log K) при использовании очереди приоритетов (т.е. Приоритетная карта).Я использовал Двухстороннюю очередь из https://github.com/pjstadig/deque-clojure
Основного кода для реализации коды в 1-е ссылки выше (для мин, а не макс):
(defn windowed-min-queue [w a]
(let [
deque-init (fn deque-init [] (reduce (fn [dq i]
(dq-push-back i (prune-back a i dq)))
empty-deque (range w)))
process-min (fn process-min [dq] (reductions (fn [q i]
(->> q
(prune-back a i)
(prune-front i w)
(dq-push-back i)))
dq (range w (count a))))
init (deque-init)
result (process-min init)] ;(process-min init)]
(map #(nth a (dq-front %)) result)))
Сравнивая скорость этого метода к другому решению, которое использует приоритет Карта у нас (примечание: мне понравилось другое решение, так как с тех пор его проще).
; Test using Random arrays of data
(def N 1000000)
(def a (into [] (take N (repeatedly #(rand-int 50)))))
(def b (into [] (take N (repeatedly #(rand-int 50)))))
(def w 1024)
; Solution based upon Priority Map (see other solution which is also great since its simpler)
(time (doall (windowed-min-queue w a)))
;=> "Elapsed time: 1820.526521 msecs"
; Solution based upon double-ended queue
(time (doall (windowed-min w b)))
;=> "Elapsed time: 8290.671121 msecs"
Что за 4 раза быстрее, что является большим учитывая PriorityMap написан на Java, в то время как код двухсторонняя очередь чисто Clojure (см https://github.com/pjstadig/deque-clojure)
В том числе других оберток/утилит, используемых на двойная очередь для ссылки.
(defn dq-push-front [e dq]
(conj dq e))
(defn dq-push-back [e dq]
(proto/inject dq e))
(defn dq-front [dq]
(first dq))
(defn dq-pop-front [dq]
(pop dq))
(defn dq-pop-back [dq]
(proto/eject dq))
(defn deque-empty? [dq]
(identical? empty-deque dq))
(defn dq-back [dq]
(proto/last dq))
(defn dq-front [dq]
(first dq))
(defn prune-back [a i dq]
(cond
(deque-empty? dq) dq
(< (nth a i) (nth a (dq-back dq))) (recur a i (dq-pop-back dq))
:else dq))
(defn prune-front [i w dq]
(cond
(deque-empty? dq) dq
(<= (dq-front dq) (- i w)) (recur i w (dq-pop-front dq))
:else dq))
Это скорее похоже на вопрос об алгоритмах, чем вопрос Clojure. Если у вас есть алгоритм, кто-то может помочь с его внедрением в Clojure. Но, как есть, это «помогите мне решить проблему интервью». – amalloy