我有3个类型::[Integer]
的列表,它们从最小到最大排序,所有任意长度和不同长度,在所有3中找到所有常见整数(如果有的话)的最有效方法是什么列表。
答案 0 :(得分:8)
我不知道这是否是最快但应该非常快。使用列表或订购的事实。
repeats :: [Integer] -> [Integer] -> [Integer] -> [Integer]
repeats [] _ _ = []
repeats _ [] _ = []
repeats _ _ [] = []
repeats a@(x:xs) b@(y:ys) c@(z:zs)
| x == y && y == z = x : repeats xs ys zs
| x <= y && x <= z = repeats xs b c
| y <= x && y <= z = repeats a ys c
| otherwise = repeats a b zs
如果所有列表的第一个元素相同,那么我们将其添加到重复列表中。否则我们丢弃任何列表的最小值然后递归。如果您有n个列表,则可能需要二进制堆等。
修改强>
尾递归版
repeatsTail :: [Integer] -> [Integer] -> [Integer] -> [Integer]
repeatsTail f s t = go f s t []
where go [] _ _ acc = reverse acc
go _ [] _ acc = reverse acc
go _ _ [] acc = reverse acc
go a@(x:xs) b@(y:ys) c@(z:zs) acc
| x == y && y == z = go xs ys zs (x:acc)
| x <= y && x <= z = go xs b c acc
| y <= x && y <= z = go a ys c acc
| otherwise = go a b zs acc
编辑2:
使用模式
答案 1 :(得分:7)
最简洁的方式可能是使用函数Data.List.intersect:
import Data.List (intersect)
intersect [1, 2, 3] (intersect [1, 2] [2, 3])
此解决方案的问题是intersect
必须多次遍历列表才能找到匹配的元素。
如果要避免这种开销,则必须至少暂时将元素存储在更有效的数据结构中。明显的,可能合理有效的解决方案是转换为集合并使用Data.Set.intersection:
import Data.Set (fromList, toList, intersection)
toList (intersection (fromList [1, 2, 3]) (intersection (fromList [1, 2]) (fromList [2, 3])))
如果列表中的元素足够小以适合Int
(而非Integer
),则可以使用Data.IntSet
代替Data.Set
来< strong>提高绩效:
import Data.IntSet (fromList, toList, intersection)
toList (intersection (fromList [1, 2, 3]) (intersection (fromList [1, 2]) (fromList [2, 3])))
如果您需要更高的性能,则必须选择适合列表中数字的数据结构。也许bitsets适用于您的用例?或者您可以尝试以UArray Int Boolean
函数使用accumArray
。
答案 2 :(得分:3)
对于简短列表,我只想使用elem
构建一些东西。您可以利用这一见解,即所有三个列表中出现的任何数字都必须出现在最短列表中:所以您只需要考虑最短列表中的所有数字。
对于较长的列表,我会将列表转换为IntSet
,然后使用intersection
:
import Data.IntSet
intersection3 :: [Int] -> [Int] -> [Int] -> [Int]
intersection3 a b c = toList $ fromAscList a `intersection` fromAscList b `intersection` fromAscList c
答案 3 :(得分:2)
这似乎也很快:
import Data.List (sort,group)
f a b c = map head
. filter (not . null . drop 2)
. group
. sort
$ a ++ b ++ c