要學習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