【问题标题】:Invert a permutation in linear time, using only lists在线性时间内反转排列,仅使用列表
【发布时间】:2011-11-30 06:59:18
【问题描述】:

我要定义一个函数

invert :: [Int] -> [Int]

假设其输入是[0..(n-1)] 的排列,并返回其逆。是否可以仅使用列表和元组(不使用数组)来定义它,使其在线性时间内运行?

这主要是出于学术兴趣;在实际代码中,我可能会使用 ArraySTArray 或类似的。

【问题讨论】:

  • 你能解释一下什么是排列列表的倒置吗?
  • 我喜欢这个问题,但我相信在 O(n) 中不可能做到。一个简单的方法需要排序。如果 Haskell 列表支持 O(1) 索引和追加,那么它是可能的。 Data.List 中的许多操作都是 O(n),因此我们在效率方面非常有限。
  • @Kenji,我认为可以使用数组。
  • dmitry,是的,当然。计数/桶排序会做到这一点。 =)

标签: list haskell permutation


【解决方案1】:

不确定线性时间,只是一个初学者笔记。

λ> (\x -> map snd $ sort $ zip x [1..(length x)]) [3,8,5,10,9,4,6,1,7,2]
[8,10,1,6,3,7,9,2,5,4]

【讨论】:

  • 谢谢,但是这使用了比较排序,所以它将是 Ω(n log n)。
  • 对了,length x可以省略,直接用[1..]压缩即可。
【解决方案2】:

所以,这不使用“仅列表”。但它似乎很合身。

import qualified Data.Vector as V

invert :: [Int] -> [Int]
invert list = V.toList $ vec V.// assocs
  where vec = V.fromList list -- better ideas for initializing vec?
        assocs = zip (map pred list) [1..]

参见the Vector package,它声称//O(n)。嗯,它说 O(n+m),但在这种情况下,n = m

我将它加载到 ghci 并得到与 dmitry 相同的答案。 :)

【讨论】:

【解决方案3】:

在我看来,你不能在线性时间内做到这一点。对于具有 O(n) 时间复杂度的实现,您需要乱序创建结果列表,我想您不能直接使用 cons-lists 来完成。

【讨论】:

  • 我也倾向于相信这一点。但是,reverse 的“明显”递归实现是二次时间,也有一个简单的线性时间实现。考虑minout :: [Int] -> Int,它接受一个不同的非负整数列表,并返回输入中存在的最小非负整数not。这也可以在线性时间内完成,但有一些巧妙之处。所以我想知道...
  • @prateek:我不确定我是否明白你的意思。当然,minout 有一个明显的线性时间实现;我什至会说这不需要太多聪明:minout = foldr (max . succ) 0。但这与invert 有什么关系? reverseinvert 的区别在于前者可以按顺序构造结果,而后者——我相信——不能。
  • 我(有点弱)的一点是,在线性时间内看起来很难用列表做的事情可能只是可能的,所以也许有一个聪明的方法来invert 我没有想到.我不知道如何在这里证明一个负面结果。 (顺便说一句,您提供的函数不会像我定义的那样计算 minout - 它计算 1 + 列表的最大元素:minout [0,2,4] 应该是 1
  • @prateek 啊,对不起:我误读了您对minout 的说明。所以,现在我很好奇:这个函数的聪明的线性时间实现(仅使用列表和元组)是什么样的?
  • 它不适合评论框,无论如何,为了让事情井井有条,我将其作为单独的问答发布:stackoverflow.com/questions/8326660/…
【解决方案4】:

由于对实际问题似乎没有肯定的答案,我会将我的作弊添加到非解决方案列表中:

invert :: [Int] -> [Int]
invert lst = take lng $ map (fromIntegral.(`mod`h)) $ iterate (`div`h)
                 $ sum $ zipWith (\k x->k*h^x) [0..] lst
  where h::Integer
        h = fromIntegral lng
        lng = length lst

【讨论】:

  • 我想知道k*h^x 在什么时候会成为一个显着的减速因素。
  • 很快,很遗憾!正如我所说,这不是一个真正的解决方案。事实上,求幂使得它比 O ( n log n ) 慢得多,更像是 O ( n ² log n )。
  • 这将是 O ( n ) 在一些具有本机任意精度取幂的假设量子计算机上...
【解决方案5】:

如果排列表示为不相交的循环列表,则

invert :: [[Int]] -> [[Int]]
invert = map reverse

以线性时间运行。 不过,我不确定是否有一种线性方式可以在不同的表示之间来回转换。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-16
    • 1970-01-01
    • 1970-01-01
    • 2011-12-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-12
    相关资源
    最近更新 更多