【问题标题】:Permutations of a list containing the same element several times多次包含相同元素的列表的排列
【发布时间】:2017-05-03 00:41:26
【问题描述】:

我必须编写一个接受两个数字的函数:

placeOneBlock 1 5
["feeee", "efeee", "eefee", "eeefe", "eeeef"]

所以它用 n * "f"-s 和 m-n * "e"-s 对 m 长列表进行了每一次排列。如果 n > 1,则“f”-s 应该像这样留在一组中:

placeOneBlock 3 10
["fffeeeeeee", "efffeeeeee", "eefffeeeee", "eeefffeeee", "eeeefffeee", "eeeeefffee", "eeeeeefffe", "eeeeeeefff"]

我写了这个函数:

placeOneBlock n m = permutations (replicate n 'f' ++ replicate (m-n) 'e') 

但这将“e”-s 视为独特的元素,因此产生的排列比我需要的多得多,如果 n > 1 也不起作用。我该怎么做?

【问题讨论】:

  • 将此视为列表的“排列”会使您的事情变得更加困难,因为您不想排列任何东西。相反,试着把它想象成一个做出非确定性选择的函数,在 Es 流中的 N 个位置中选择一个来放置 Fs 块。不确定性由可能的结果列表很好地建模,因此您最好编写一个使用该列表并生成一个列表作为输出的递归函数。

标签: haskell combinations permutation


【解决方案1】:

这里有一个提示。

每个可能的组合都有一些 E、一些 F 和一些 E,按此顺序排列。即,它是这种形式

replicate k 'e' ++ replicate n 'f' ++ replicate (m-n-k) 'e'

现在,使用列表推导将k 范围设置在“正确”区间上,就完成了。

【讨论】:

  • 但是如何在 haskell 中使 k 范围超过 m-n?
  • "使用列表理解"
【解决方案2】:

正如我在评论中提到的,这根本不是排列问题。相反,您想遍历输入流,恰好选择一个位置来插入插入字符块。如果输入流为空,则别无选择,必须在末尾插入块。否则,您可以选择在当前位置插入块,或者稍后再插入,在这种情况下,您可以在块之前从主流中再添加一项。

block :: a -> a -> Int -> Int -> [[a]]
block stream interloper width = go
  where go 0 = [replicate width interloper]
        go n = (replicate width interloper ++ replicate n stream)
               : ((stream :) <$> go (n - 1))

placeOneBlock :: Int -> Int -> [String]
placeOneBlock = block 'e' 'f'

This solution is a bit more complicated than chi's answer, which proposes to write something like replicate x 'e' ++ replicate y 'f' ++ replicate z 'e' for all appropriate choices of x/y/z.我的解决方案的一个优点是修改处理多个块对象而不是一个或其他一些指示块合法位置的规则要简单得多。但是,如果您没有预料到这种变化,那么 chi 的解决方案对我来说听起来不错。

【讨论】:

    【解决方案3】:

    我想这与排列无关。这是一个简单的拆分和插入所有位置的工作。您可以按如下方式实现;

    allSplits :: Int -> Int -> [String]
    allSplits 0 m = [replicate m 'e']
    allSplits n m | n >= m    = [fs]
                  | otherwise = (fs ++ replicate (m-n) 'e') : map ('e':) (allSplits n (m-1))
                    where fs  = replicate n 'f'
    

    【讨论】:

      【解决方案4】:

      这是工作代码:

      placeOneBlock 0 m = [replicate m 'e']
      placeOneBlock n m | n == m    = [fs] 
       | n > m = []
       | otherwise = (fs ++ replicate (m-n) 'e') : map ('e':) (placeOneBlock n (m-1))
                  where fs  = replicate n 'f'
      

      【讨论】:

      • 您能否编辑您的答案以添加为什么这样有效并解释您所做的更改?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-02-07
      相关资源
      最近更新 更多