在小于O(n ^ 2)

时间:2017-03-04 23:40:43

标签: algorithm haskell permutation agda dependent-type

写在Haskell中,这里的数据类型证明一个列表是另一个列表的排列:

data Belongs (x :: k) (ys :: [k]) (zs :: [k]) where
  BelongsHere :: Belongs x xs (x ': xs)
  BelongsThere :: Belongs x xs xys -> Belongs x (y ': xs) (y ': xys)

data Permutation (xs :: [k]) (ys :: [k]) where
  PermutationEmpty :: Permutation '[] '[]
  PermutationCons :: Belongs x ys xys -> Permutation xs ys -> Permutation (x ': xs) xys

使用Permutation,我们现在可以置换记录:

data Rec :: (u -> *) -> [u] -> * where
  RNil :: Rec f '[]
  (:&) :: !(f r) -> !(Rec f rs) -> Rec f (r ': rs)

insertRecord :: Belongs x ys zs -> f x -> Rec f ys -> Rec f zs
insertRecord BelongsHere v rs = v :& rs
insertRecord (BelongsThere b) v (r :& rs) = r :& insertRecord b v rs

permute :: Permutation xs ys -> Rec f xs -> Rec f ys
permute PermutationEmpty RNil = RNil
permute (PermutationCons b pnext) (r :& rs) = insertRecord b r (permute pnext rs)

这很好用。但是,置换是O(n^2),其中n是记录的长度。我想知道是否有办法通过使用不同的数据类型来表示排列,从而使它更快。

为了进行比较,在可变和无类型设置中(我知道确实是非常不同的设置),我们可以在O(n)时间内对这样的异构记录应用排列。您将记录表示为值数组,将排列表示为新位置数组(不允许重复,所有数字必须介于0和n之间)。应用置换只是迭代该数组并索引到具有这些位置的记录数组中。

我不希望在更严格的类型设置中可以O(n)排列。但似乎O(n*log(n))似乎是可能的。我感谢任何反馈,如果我需要澄清任何事情,请告诉我。此外,答案可以使用Haskell,Agda或Idris,具体取决于与之通信的方式。

1 个答案:

答案 0 :(得分:1)

更简单的解决方案是比较排列的排序排列。

  1. 给出排列A和B。

  2. 然后存在已排序的排列,

    As = sort(A)   Bs = sort(B)

  3. A和B的排列是B的排列。

  4. 如果As == Bs则A是B的排列。

  5. 因此,该算法的顺序是O(n log(n))< O(N²)

    这导致了最佳解决方案。

    使用不同的排列存储会产生O(n)

    使用上面的陈述,我们将每个排列的存储格式改为

    • 排序数据
    • 原始未分类数据

    为了确定列表是否是另一个列表的排列,需要简单地比较排序数据 - >为O(n)。

    这正确地回答了问题,但是在创建双倍数据存储时隐藏了这些努力^^因此,如果这是一个真正的优势,它将取决于使用。