我正在做一个课堂练习,经过一段时间的绞尽脑汁,我找到了理论上的方法来做它,但无法找出如何在Haskell中做。
这项工作是:
有一个列表xs
,其中有n
个不同的元素。列表xs
的n
元素的组合将它们从m
带到m
(带有m <= n
),是可以从原始n
元素形成的所有可能的m
元素集(没有重复)。
元素的顺序并不重要(这意味着"abc"
被认为是与"bca"
相同的组合)。
举例来说:
comb 0 "abcd" -> [""]
comb 3 "bcd" -> ["bcd"]
comb 2 "bcd" -> ["cd","bd","bc"]
comb 3 "abcd" -> ["bcd", "acd", "abd", "abc"]
定义一个函数comb
,它接受一个自然数m
和一个包含n
个不同元素的列表xs
。
我能找到的唯一方法是,我需要一个值,它将我的“位置指针”pp
,这样它将删除该指针之后的length xs - m
元素,然后在递归调用中做m + pp
,所以它“跳”到下一个位置。我将以一种伪Haskell的方式写一个例子:
m = 3 xs = "abcd" * = pp
*abcd *remove (length xs - m) after pointer
Solution: "bcd"
*Recursively jump pointer by (length xs - m):
"a*bcd" -> "acd"
"ab*cd" -> "abd"
"abc*d" -> "abc"
"abcd*" -> [""]
我真的很抱歉这种发明,我试图使用指针类比,因为我认为这是很容易看到它的方式,我用我的伪代码和Haskell的混合,因为不知道如何做它的另一种方式。
2条答案
按热度按时间d8tt03nd1#
如何从列表中选择
n
元素?如果
n
为零,那么无论列表是什么,都只有一个没有元素的pick。否则,如果你的列表是空的,你根本没有选择。(注意这与上面的不同。
否则,你的列表就有一个头和一个尾。选择如下。首先,你有所有的选择,包括头,然后所有的选择,不包括头。
如何构建所有不包括头部的选择?这很简单,只需将函数递归地应用于列表的尾部。
包括头部的选择呢?这也很简单,只需将函数递归地应用于列表的尾部,但这次要将picks缩短一个元素。然后在每个拨片前面拍一下头。
wsxa1bj12#
基本上你可以做的就是每次选择一个元素,然后继续添加元素。
为了防止 * 对称 *,我们可以说,如果我们在位置 i 选择一个字符,我们只能选择位置 i 右侧的项目,所以这意味着我们将列表中的 * 其余 * 字符作为递归传递。
我们可以先构造一个helper函数,对于一个给定的列表
[a]
,返回一个2元组[(a, [a])]
的列表,其中包含选中的项和其余的项,所以:在这里,我把填写
…
部分作为练习。对于[1,4,2,5]
,它应该返回[(1, [4,2,5]), (4, [2,5]), (2, [5]), (5, [])]
,因为我们可以选择任何元素,并且每次在我们选择的元素的右侧都有一个剩余元素的列表,我们可以使用它来选择其他元素。现在我们有了它,我们可以做一个递归函数来挑选 n 个元素。我们通过检查还有多少项目需要挑选来做到这一点。对于没有项目,我们返回一个单一的项目:空的名单。对于 n 个项目,我们选择一个项目并递归 n-1 个项目:
我们可以进一步提升这个算法,只选择那些在选择后仍有 n-1 个元素的元素。我也把它作为一个练习。
因此,我们在这里 * 不 * 需要列表的长度,我们可以只选择元素。如果初始列表具有无限长,这甚至会产生结果:如果我们需要 m 个项目,它最终将返回 [x1,x2,...,xm-1,xn],并因此产生结果,尽管对于上述实现,它永远不会产生以 [x1,x3,...] 开头的结果。