要学习Haskell我一直在解决编程挑战。在尝试解决在Hackerrank中发现的一个过滤千位元素列表中的元素的问题时,我一直无法通过时间测试。如何优化列表过滤
的问题陈述是:从元素列表过滤那些出现次数大于ķ倍,并在其出现的顺序打印出来。
到目前为止,我已经来最好的是这样的代码:
import qualified Data.ByteString.Char8 as BSC
import Data.Maybe (fromJust)
import Data.List (intercalate, elemIndices, foldl')
import qualified Data.Set as S
-- Improved version of nub
nub' :: (Ord a) => [a] -> [a]
nub' = go S.empty
where go _ [] = []
go s (x:xs) | S.member x s = go s xs
| otherwise = x : go (S.insert x s) xs
-- Extract Int from ByteString
getIntFromBS :: BSC.ByteString -> Int
getIntFromBS = fst . fromJust . BSC.readInt
{-
Parse read file:
a k1
n1 n2 n3 n4 ...
c k2
m1 m2 m3 m4 ...
into appropriate format:
[(k1, [n1,n2,n3,n4]), (k2, [m1,m2,m3,m4])]
-}
createGroups :: [BSC.ByteString] -> [(Int, [Int])]
createGroups [] = []
createGroups (p:v:xs) =
let val = getIntFromBS $ last $ BSC.split ' ' p
grp = foldr (\x acc -> getIntFromBS x : acc) [] $ BSC.split ' ' v
in (val, grp) : createGroups xs
solve :: (Int, [Int]) -> String
solve (k, v) = intercalate " " $ if null res then ["-1"] else res
where
go n acc =
if length (elemIndices n v) > k
then show n : acc
else acc
res = foldr go [] (nub' v)
fullSolve :: [BSC.ByteString] -> [String]
fullSolve xs = foldl' (\acc tupla -> acC++ [solve tupla]) [] $ createGroups xs
main = do
BSC.getContents >>= mapM_ putStrLn . fullSolve . drop 1 . BSC.lines
我想知道我在哪里可以改进此代码。我已经尝试了很多使用地图,向量,解析的变体,并且不从文件解析读取的字符串到Int
,但显示的代码是我拥有的最好的代码。
'acC++ [解决tupla]'部分让我感到担心,这会导致运行时性能下降。考虑在这里使用'Data.Seq'而不是 – bheklilr 2014-10-31 18:23:29
您能否解释为什么特定部分会担心您?你是怎么注意到它的? – OneEyeQuestion 2014-10-31 18:27:18
将单个元素连接到单个链表(Haskell列出的内容)的末尾是O(n)操作。每次添加元素时都必须遍历整个列表。预先考虑(或考虑)一个元素是O(1)。阅读Haskell代码时,这些细节非常突出,'++ [单元素]'变得非常引人注目并带有丰富的经验。 – bheklilr 2014-10-31 18:31:46