在Haskell中具有重复项的交叉点的快速长度

时间:2015-05-11 22:28:47

标签: list haskell optimization

我正在写一个mastermind求解器,在内循环中我计算两个列表的intersection with duplicates的长度。现在我的功能是

overlap :: Eq c => [c] -> [c] -> Int
overlap [] _ = 0
overlap (x:xs) ys
    | x `elem` ys = 1 + overlap xs (delete x ys)
    | otherwise = overlap xs ys

是否可以加快速度?如果有帮助,overlap的参数是相同长度的短列表,最多6个元素,而c类型的可能值少于10个。

2 个答案:

答案 0 :(得分:2)

通常,(几乎)不可能提高此类算法的性能:为了删除两个无序不可用列表中的重复项,可以在< EM>为O(n ^ 2)

通常,您可以通过以下条件(每种条件,不同的方法)提高性能:

  • 如果您可以确保为每个列表创建/修改/ ...,则保持元素的顺序;这可能需要一些工程。在这种情况下,算法可以在O(n)中运行。

    在这种情况下,您可以使用以下命令运行它:

    --Use this only if xs and ys are sorted
    overlap :: Ord c => [c] -> [c] -> Int
    overlap (x:xs) (y:ys) | x < y = overlap xs (y:ys)
                          | x > y = overlap (x:xs) ys
                          | otherwise = 1 + overlap xs ys
    overlap [] _ = 0
    overlap _ [] = 0
    

    通常,列表的排序可以在 O(n log n)中完成,因此比 O(n ^ 2)重叠算法更有效。新的重叠算法在 O(n)

  • 中运行
  • 如果订购了c,您也可以使用Data.Set。在这种情况下,您可以使用在 O(n log n)中运行的fromList方法为两个列表创建TreeSet,然后使用intersection函数计算在 O(n)时间内交叉,最后使用size函数计算大小。

    --Use this only if c can be ordered
    overlap :: Ord c => [c] -> [c] -> Int
    overlap xs ys = size $ intersection (fromList xs) (fromList ys)
    

答案 1 :(得分:0)

您是否对多个ys使用相同的xs

如果是,您可以尝试计算ys中每个元素的哈希值并匹配此值,但请记住,计算哈希需要比6次比较更快。

如果其中任何一个是Ord,您也可以提前对其进行排序,并仅验证ys的必要部分。

但是,如果您需要快速随机访问列表不是最佳结构,您应该查看Data.ArrayData.HashMap