【问题标题】:Permutation of a list in haskellhaskell中列表的排列
【发布时间】:2014-09-28 20:52:22
【问题描述】:

我们有两个列表xs :: [a]ys :: [Int]。例如:

xs = ["some", "random", "text"]
ys = [2, 3, 1]

我们必须生成一个新列表zs :: [a],这样zs 是使用ys 生成的xs 的排列。对于上面的例子:

zs = ["random", "text", "some"]

解释:“random”出现在xs的第二个位置,“text”出现在第三个位置,“some”出现在第一个位置。

到目前为止,我已经得出了这个解决方案:

f :: [a] -> [Int] -> [a]
f xs ys = getList (listArray (1, n) xs) ys where
  n = length xs
  getList :: Array Int a -> [Int] -> [a]
  getList a ys = [ a ! x | x <- ys]

f 是否有更好的定义可以避免使用数组?我正在寻找内存高效的解决方案。如果xs 是一个大字符串列表,那么数组是一个糟糕的选择。 f 的时间复杂度可以放宽到 O(n log n)

【问题讨论】:

  • Array 有什么问题?
  • 你可以压缩和排序,或者构造一个Map Int a,但无论哪种方式都会产生一个额外的log(n)因素。
  • 假设 n 很大,比如 10^6。我正在寻找一种解决方案,它需要最少的额外内存,但仍保持 O(n) 复杂度。
  • @ChrisMartin:在进行压缩和排序之前,我需要反转 ys stackoverflow.com/q/8322238/1843751
  • 我不相信Array 的内存效率低于这里的其他解决方案,因为您没有希望获得真正的“流式传输”解决方案。请注意,即使xs 包含大字符串,它们也不会被复制到数组中,而只是对它们的引用。因此,额外的内存开销不一定比构建需要包含 cons 单元的压缩列表之类的东西高。 (我不认为要排序的列表可以融合掉。)

标签: algorithm list haskell permutation


【解决方案1】:

只需来回排序两次,就可以完成这项工作:

import Data.Ord
import Data.List

f :: [a] -> [Int] -> [a]
f xs = map fst . sortBy (comparing snd) . zip xs . 
       map fst . sortBy (comparing snd) . zip ([1..] :: [Int]) 

这样

Prelude Data.Ord Data.List> f ["some", "random", "text"] [2, 3, 1]
[“随机”,“文本”,“一些”]

(使用this answer的想法)。

由于我们两次都对Int 索引进行排序,因此您可以使用一些整数排序(如基数排序)来获得O(n) 解决方案。

【讨论】:

    猜你喜欢
    • 2021-09-04
    • 2021-03-07
    • 1970-01-01
    • 1970-01-01
    • 2017-02-27
    • 1970-01-01
    • 2021-08-06
    • 1970-01-01
    • 2015-12-09
    相关资源
    最近更新 更多