【发布时间】:2017-05-29 02:36:44
【问题描述】:
我决定尝试通过做一些CodinGame 挑战来学习 Haskell(所以我敢肯定这个问题是超级初学者级别的东西)。其中之一需要在整数列表中搜索任意两个值之间的最小差异。我以前通过这样做在 Clojure 中解决了它:
(ns Solution
(:gen-class))
(defn smallest-difference [values]
(let [v (sort values)]
(loop [[h & t] v curr-min 999999]
(if (nil? t) curr-min
(let [dif (- (first t) h)]
(recur t (if (> curr-min dif) dif curr-min)))))))
(defn -main [& args]
(let [horse-strengths (repeatedly (read) #(read))]
(let [answer (smallest-difference horse-strengths)]
(println answer))))
我尝试在 Haskell 中实现相同的解决方案,如下:
readHorses :: Int -> [Int] -> IO [Int]
readHorses n h
| n < 1 = return h
| otherwise = do
l <- getLine
let hn = read l :: Int
readHorses (n - 1) (hn:h)
findMinDiff :: [Int] -> Int -> Int
findMinDiff h m
| (length h) < 2 = m
| (h!!1 - h!!0) < m = findMinDiff (tail h) (h!!1 - h!!0)
| otherwise = findMinDiff (tail h) m
main :: IO ()
main = do
hSetBuffering stdout NoBuffering -- DO NOT REMOVE
input_line <- getLine
let n = read input_line :: Int
hPrint stderr n
horses <- readHorses n []
hPrint stderr "Read all horses"
print (findMinDiff (sort horses) 999999999)
return ()
对于 Clojure 解决方案没有的大输入(99999 个值)会超时。然而,它们看起来和我很相似。
至少从表面上看,读取值和构建列表似乎不是问题,因为“读取所有马匹”是在超时之前打印的。
如何使 Haskell 版本的性能更高?
【问题讨论】:
-
length h < 2将遍历整个列表。我会为[]和[_]使用模式匹配,即使这需要少量重复。 (在最后一种情况下,我会使用(x1:x2:xs)并避免部分使用!!- 这不会提高速度,但它更习惯用语) -
谢谢!我非常感谢 findMindDiff 的示例实现,它说明了这个@chi。
标签: performance haskell recursion clojure