如何改进我对Hackerrank Maximum Element挑战的解决方案以避免超时?

时间:2017-10-04 14:44:48

标签: clojure

我正在尝试完成此处发现的Hackerrank Maximum Element挑战:https://www.hackerrank.com/challenges/maximum-element/problem

我的解决方案产生正确的输出,但是以#17开头的最终测试用例超时。

最初,我使用了list和loop / recur来得到我的答案:

(defn get-query [] 
  (map #(Integer/parseInt %) (clojure.string/split (read-line) #" ")))

(defn stack-stepper [query stack]
  (condp = (first query)
    1 (conj stack (second query))
    2 (rest stack)
    3 (do (println (apply max stack)) stack)))

(loop [stack '()
       queries-left (Integer/parseInt (read-line))]
  (if (> queries-left 0)
    (recur (stack-stepper (get-query) stack) (dec queries-left))))

经过一些研究和其他渠道的反馈,我尝试了一个向量而不是一个列表,并减少而不是循环/重复,但结果是相同的。

(defn get-query [] 
  (map #(Integer/parseInt %) (clojure.string/split (read-line) #" ")))

(defn get-queries []
  (loop [queries      []
         queries-left (Integer/parseInt (read-line))]
    (if (= queries-left 0)
      queries
      (recur (conj queries (get-query)) (dec queries-left)))))

(defn stack-stepper [stack query]
  (condp = (first query)
    1 (conj stack (second query))
    2 (pop stack)
    3 (do (println (apply max stack)) stack)))

(reduce stack-stepper [] (get-queries))

我还是FP和Clojure的新手,我真的很想了解我所缺少的东西。非常感谢您的时间和帮助!

1 个答案:

答案 0 :(得分:3)

从性能的角度来看,HackerRank问题通常非常苛刻。

首先尝试的显而易见的事情是使用瞬态向量,看看是否有帮助。我试过这个:

(let [in (clojure.string/split (slurp *in*) #"\s")
         tests (first in)
         input-data (map #(Integer/parseInt %) (rest in))]

  (loop [v (transient [])
         d input-data]
    (when (seq d)
      (condp = (first d)
        1 (recur (conj! v (second d)) (drop 2 d))
        2 (recur (pop! v) (rest d))
        3 (let [pv (persistent! v)] (println (apply max pv)) (recur (transient pv) (rest d)))))))

如果与您的解决方案同时失败。很显然,他们正在寻找比这更聪明的东西。

明显的瓶颈是计算当前堆栈的最大值,每次都会重新计算。我们可以将先前的最大值保存在堆栈上,并在弹出堆栈时将其恢复为当前最大值:

(defn peek! [tvec] (get tvec (dec (count tvec))))

(let [in (clojure.string/split (slurp *in*) #"\s")
         tests (first in)
         input-data (map #(Integer/parseInt %) (rest in))]

    (loop [v (transient [])
             m 0
             d input-data]
        (when (seq d)
          (condp = (first d)
            1 (let [snd (second d)
                    max-now (max m snd)]
                (recur (conj! v {:val snd :max-prev m}) max-now (drop 2 d)))

            2 (let [popped (peek! v)
                    max (if popped (:max-prev popped) 0)]
                (recur (pop! v) max (rest d)))

            3 (do
                (println m)
                (recur v m (rest d)))))))

这使我在排行榜上排名第一:)