【发布时间】:2017-10-19 15:02:34
【问题描述】:
我目前正在解决 Project Euler 中的一些问题,作为我的 Common Lisp 学习例程的一部分。我不会提及它与该网站的精神是什么问题。
我遇到的问题是我的代码适用于小输入,但会冻结大输入。具体来说,它会在获得答案所需的相同数量级冻结,但在低于该数量级的情况下成功运行。
问题描述如下:给定一组数字,形成这些数字的所有可能排列,然后对结果进行数字排序并选择结果集中的第 n 个成员。
我将按如下方式运行以下代码。
例如,如果我想获得数字(1, 2, 3) 的第三个排列,我会拨打电话:
CL-USER> (number-permutations '(1 2 3) 3)
213
另一个例子是:
CL-USER> (number-permutations '(0 1 2 3 5) 100)
50231
代码适用于此:
CL-USER> (number-permutations '(0 1 2 3 5 6 7 8) 100)
1283675
但此调用冻结(或耗时过长):
CL-USER> (number-permutations '(0 1 2 3 5 6 7 8 9) 1000000)
我的问题有两个。我在做什么低效导致计算需要这么长时间?我是否遇到了 Lisp 实现(SBCL)的一些限制?怎样才能让计算在合理的时间内完成?
代码:
;;; How to make permutations of a list
;;;
;;; all permutations of a list L is:
;;; for each element E in L:
;;; that element prepended to all permutations of [ L with E removed ]
(defun permutation (digits)
;if the list is null or empty, return NIL
(cond ((null digits) nil)
;if the list consists of one element, return the list of one element
((null (cdr digits)) (list digits))
; cycle through every element in list and append
; that element to all permutations of a list of elements
; with the current element removed
(t (loop for element in digits
append (mapcar (lambda (l) (cons element l))
(permutation (remove element digits)))))))
(defun list-to-number (list)
(loop for item in list for i from (- (list-length list) 1) downto 0
summing (* (expt 10 i) item)))
(defun number-permutations (digits n)
(car (nthcdr (- n 1)
(sort (loop for item in (permutation digits)
collecting (list-to-number item))
#'<))))
【问题讨论】:
-
n数字的排列数是n!所以如果,正如你所写的(虽然我的 LISP 生锈了,我还没有检查过),你的代码形成所有排列然后选择 @ 987654330@-th,即使n显然很小,您的处理器也会崩溃也就不足为奇了。您确定问题陈述要求您形成所有排列的列表吗?通常这个问题是通过找到k-th 排列而不找到所有其他排列来解决的——这是对你的狡猾的考验,而不是你的处理器的能力。 -
不,我不确定。我所描述的是我对问题的理解,这可能被我对如何解决它的思考所破坏。你可能是正确的需要更狡猾:)
-
我想我使用这里找到的算法解决了这个问题:cut-the-knot.org/do_you_know/AllPerm.shtml 在 CodeReview 上,您可以找到我最初的尝试以及一些关于编码风格和效率的非常有价值的方法。
-
另外一件事,经过仔细观察:OP 的最后一个测试用例似乎在寻找一组
9元素的1,000,000-th 排列。棒棒糖,让第一个知道为什么这可能导致最聪明的算法失败的人...... -
你说的是9! = 578880
标签: algorithm performance optimization lisp common-lisp