我正在学习Scheme,我正在尝试以一定的大小重复生成排列。
例如,给定n = 4并设置S = {a,b,c,d,e,f},我想生成所有可能的排列:{a,a,a,a},{a中,a,A,b},...,{A,A,A,F},{A,A,b,A},{A,A,b,b},...,{A,A ,b,F},... {F,A,A,A},{F,A,A,b} ...,{F,A,A,F},... {F,F, F,F}。
麻烦的是,我无法理解如何选择'a'4次,并记住我已经选择了4次,然后选择'a'3次,'b'一次,并记住这一切,所以我不再选择了。
我知道这些问题最好通过递归算法来解决,但它只会使一切变得更复杂,例如,我如何记住递归,我选择了哪些元素。
我根本不知道如何解决这个问题。如果有人写出解决这个问题的思考过程,我会很高兴。我非常感激!
请帮帮我。
谢谢,Boda Cydo。
答案 0 :(得分:4)
从程序的界面和预期结果开始是很好的。您的程序将被称为(permutations size elements)
,并且应该返回ELEMENTS中项目的排列列表,每个排列长度为SIZE项目。如图所示,您将以列表形式表示“排列”。因此,如果您拨打(permutations 1 '(a b c))
,则预计输出为((a) (b) (c))
。
所以关于递归过程的技巧,你必须弄清楚你可以轻松回答的基本条件是什么,以及你可以通过修改更简单问题的解决方案来回答的递归步骤。对于PERMUTATIONS,计算递归步骤将涉及减小SIZE,因此基本步骤将是当SIZE为0时,并且答案是零长度置换的列表,即。即(())
。
要回答递归步骤,你必须弄清楚如何处理大小为N-1的结果以获得大小为N的结果。为此,它可以帮助写出小N的一些预期结果看看你是否能辨别出一种模式:
ELEMENTS = (a b) SIZE (PERMUTATIONS SIZE ELEMENTS) 0 ( () ) 1 ( (a) (b) ) 2 ( (a a) (a b) (b a) (b b) ) 3 ( (a a a) (a a b) (a b a) (a b b) (b a a) ... )
所以基本上你要做的是,给定R = (permutations n elements)
,你可以通过在R中取每个排列P得到(permutations (+ n 1) elements)
,然后对于ELEMENTS中的每个元素E,将E连接到P创建一个新的排列,并收集它们的列表。我们可以使用嵌套MAP执行此操作:
(define (permutations size elements) (if (zero? size) '(()) (flatmap (lambda (p) ; For each permutation we already have: (map (lambda (e) ; For each element in the set: (cons e p)) ; Add the element to the perm'n. elements)) (permutations (- size 1) elements))))
我正在使用FLATMAP进行外部映射,因为内部MAP会创建新排列的列表,我们必须将这些列表附加在一起,以创建我们想要的一个大的排列列表。
当然,这都是假设你知道并且很好地处理像MAP这样的序列操作。如果你不这样做,那就像我刚刚在这里做出的优雅解决方案一样真的很难。
答案 1 :(得分:1)
这是另一个版本:我使用的是reduce,而不是flatmap。我是在MIT-scheme
写的。
(define (per s)
(define (ins c before after)
(if (null? after)
(list (append before (list c)))
(append (list (append before (list c) after))
(ins c
(append before (list (car after)))
(cdr after)))))
(define (iter l)
(cond ((null? l)
'(()))
(else
(let ((rest (iter (cdr l))))
(reduce-left append
()
(map (lambda (x) (ins (car l) () x) )
rest))))))
(iter s))
(per '(1 3 2 4))
答案 2 :(得分:0)
提示:您可以使用参数进行递归调用以“记住”其他递归调用已完成的操作。 ;)