【问题标题】:Common Lisp Code Freezes or Needs to Be OptimizedCommon Lisp 代码冻结或需要优化
【发布时间】: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


【解决方案1】:

正如High Performance Mark的评论所述,所以这个问题可以结束了:

我在做什么效率低下导致计算需要这么长时间?
你做n! 计算,n 是一个数字。 1000000! 大约等于 8.26×105565708(请参阅 Quora 以获得很好的解释),所以难怪你的计算机无法处理它;)

我是否遇到了 Lisp 实现 (SBCL) 的一些限制?
也许吧,但你的 RAM 很可能最先出现故障。

怎样才能让计算在合理的时间内完成?
再做一次计算。 Project Euler 练习的重点通常是找到解决问题的聪明方法,而不是暴力破解。

祝你好运!

【讨论】:

  • 为了公平起见,他的 (?) 问题不是寻找1000000! 排列,而是寻找1000000-th 出9! 排列。这就引出了另一件事。
  • 对。我的坏:/
猜你喜欢
  • 2011-02-04
  • 1970-01-01
  • 1970-01-01
  • 2014-06-10
  • 2018-02-21
  • 2012-10-19
  • 1970-01-01
  • 2011-11-06
  • 1970-01-01
相关资源
最近更新 更多