查找"计算序列"

时间:2017-08-08 05:52:33

标签: algorithm haskell

给定一个整数列表xs,让:

count :: [Integer] -> Integer -> Integer
count xs n = length . filter (==n) $ xs

计算列表中出现整数n的次数。

现在,给出一个"列表" (长度为n的某种整数数组,可以是除List之外的东西),写一个函数

countSequence :: [Integer] -> Integer -> Integer -> Integer
countSequence xs n m = [count xs x | x <- [0..m]]

输出&#34;计数列表&#34; (第0个索引包含列表中出现0的次数,第1个索引包含列表中出现1次的次数等)具有时间完整性o(m * n)

我给出的上述实现具有复杂度O(m * n)。在Python(我更熟悉)中,在O(m + n)时间内很容易做到这一点 - 遍历列表,每个元素在其他列表中增加一个计数器,初始化为全零和长度(m + 1)。

如何在Haskell中获得更好的实现?如果实现Python解决方案不是一些微不足道的方法(比如在函数中添加另一个输入以保持&#34;计数列表&#34; in然后通过它进行交互),我更喜欢

3 个答案:

答案 0 :(得分:2)

O(n+m)(有点,我想,也许):

import Data.Ix (inRange)
import qualified Data.IntMap.Strict as IM

countSequence m =
  foldl' count IM.empty . filter (inRange (0,m))
    where count a b = IM.insertWith (+) b 1 a

给出

> countSequence 2 [1,2,3,1,2,-1]
fromList [(1,2),(2,2)]

我还没有使用n,因为你也没有使用n而且我不确定它应该是什么。我还将列表移动到最后一个参数,使其处于减少的位置。

答案 1 :(得分:1)

我认为你应该使用你的Python直觉 - 遍历一个列表并在另一个列表中增加一个计数器。这是O(n + m)运行时的实现:

import Data.Array
countSequence xs m = accumArray (+) 0 (0,m) [(x, 1) | x <- xs, inRange (0,m) x]

(这个用例甚至是文档中存在accumArray的动机示例!)在ghci中:

> countSequence ([1..5] ++ [1,3..5] ++ [1,4..5] ++ [1,5]) 3
array (0,3) [(0,0),(1,4),(2,1),(3,2)]

答案 2 :(得分:1)

我想使用Data.IntMap会有效地完成这项工作。完成一次foldr次传递以建立IntMapcm)和map以构建一个新列表,其中包含相应位置的元素计数。

import qualified Data.IntMap.Lazy as IM

countSequence :: [Int] -> [Int]
countSequence xs = map (\x -> let cm = foldr (\x m -> IM.alter (\mx -> if mx == Nothing then Just 1 else fmap (+1) mx) x m) IM.empty xs
                              in IM.findWithDefault 0 x cm) xs

*Main> countSequence [1,2,5,1,3,7,8,5,6,4,1,2,3,7,9,3,4,8]
[3,2,2,3,3,2,2,2,1,2,3,2,3,2,1,3,2,2]
*Main> countSequence [4,5,4]
[2,1,2]
*Main> *Main> countSequence [9,8,7,6,5]
[1,1,1,1,1]