如何改进Haskell组合算法?
如何改进以下问题的解决方案?它能在时间和空间上更有效吗?有空间泄漏吗 问题: 给定一份输入的如何改进Haskell组合算法?,haskell,ghc,Haskell,Ghc,如何改进以下问题的解决方案?它能在时间和空间上更有效吗?有空间泄漏吗 问题: 给定一份输入的宇航员列表,生成一份成对的宇航员列表,这样成对的宇航员就不会有来自同一国家的两名宇航员。假设输入有一个带有唯一标识符的宇航员列表 data Astronaut = Astronaut { identifier :: Int, country :: String } deriving (Eq) astronautPairs :: [Astronaut] -> [(Astronaut, Astrona
宇航员列表
,生成一份成对的宇航员列表
,这样成对的宇航员就不会有来自同一国家的两名宇航员。假设输入有一个带有唯一标识符的宇航员列表
data Astronaut = Astronaut { identifier :: Int, country :: String } deriving (Eq)
astronautPairs :: [Astronaut] -> [(Astronaut, Astronaut)]
astronautPairs xs = foldl accumulatePairs [] [(a, b) | a <- xs, b <- xs, country a /= country b]
where
accumulatePairs pairs pair = if hasPair pair pairs then pairs else pair:pairs
hasPair pair@(a,b) ((c,d):xs) = a == d && b == c || hasPair pair xs
hasPair _ [] = False
数据宇航员=宇航员{identifier::Int,country::String}派生(Eq)
宇航员对::[宇航员]->[(宇航员,宇航员)]
让我们从实现细节后退一步,思考一下您试图实现的目标:
制作一份成对的宇航员
s的列表,这样成对的宇航员就不会有来自同一国家的两名宇航员
s
你似乎可以假设每个宇航员在名单中只出现一次
解决这个问题的一个有效方法是从按国家划分列表开始。一个自然的方法是构建一个包含每个国家所有宇航员列表的HashMap字符串[Int]
import qualified Data.HashMap.Strict as HMS
import Data.HashMap.Strict (HashMap)
divideAstronauts :: [Astronaut] -> HashMap String [Int]
divideAstronauts = foldl' go mempty where
go hm (Astronaut ident cntry) = HMS.insertWith (++) cntry [ident] hm
现在,您可以将程序的其余部分分为两个步骤:
选择所有国家/地区对
对于每一对国家,选择每一对来自其中一个国家的宇航员
与其消除翻转对,为什么不首先避免生成它们。是我们生成了它们,是吗
import Data.List (tails)
astronautPairs :: [Astronaut] -> [(Astronaut, Astronaut)]
astronautPairs xs = [ (y,z) | (y:ys) <- tails xs, z <- .... , country y /= country .... ]
导入数据列表(尾部)
宇航员对::[宇航员]->[(宇航员,宇航员)]
你认为它应该占用多少空间?一旦你决定了,只需在一个大的输入上运行你的代码,看看你的内存使用情况是否匹配(这里可以使用-stderr
运行时选项)。然后告诉我们它是否有空间泄漏。您可能喜欢中的pairs
函数。是否同时生成(a,b)
和(b,a)
,或者你打算代表两人团队吗?是的,我觉得这很正确。这个团队的空间复杂度是多少?当然,时间是二次的。空间将取决于最终列表的长度。没有什么可以阻止编译器生成除O(n)外还可以在O(1)空间中工作的代码必须完全存在于内存中的输入列表的大小——也就是说,这不是一个在线算法,即使在访问最后一个元素时,GC也无法回收列表的头元素。