下面介绍的解决方案如何改进以下问题?它能在时间和空间上更有效吗?是否有空间泄漏?
问题:
给定Astronauts
的输入列表,生成Astronauts
对的列表,使得这些对没有来自同一国家/地区的两个Astronauts
。假设输入的列表Astronauts
具有唯一identifier
s。
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
答案 0 :(得分:2)
而不是消除翻转对,为什么不首先避免生成它们。是我们生产它们,是吗?
import Data.List (tails)
astronautPairs :: [Astronaut] -> [(Astronaut, Astronaut)]
astronautPairs xs = [ (y,z) | (y:ys) <- tails xs, z <- .... , country y /= country .... ]
这假定宇航员的输入列表没有重复。
因此,我们通过三角形生成来避免重复。
(我留下了部分代码,供您完成)。
答案 1 :(得分:0)
让我们从实施细节中退一步,思考一下你想要实现的目标:
生成
Astronaut
对的列表,以使这些对没有来自同一个国家/地区的两个Astronaut
您似乎可以假设每个宇航员只在列表中出现一次。
解决此问题的一种有效方法是首先按国家分区列表。一种自然的方法是建立一个HashMap String [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
现在,您可以将程序的其余部分分为两个步骤: