生成按递减顺序排列的Lucas数列表(使用let)



Lucas数与Fib数相似,只是它以2开头而不是1:

 2, 1, 3, 4, 7, 11, 18,

我想写一个函数,生成一个卢卡斯级数列表,按递减顺序排列,直到第n个元素。

我写了这个,但我追踪了它,它太慢了,无法实现到我的列表构建功能中。

(defun lucas (n)
  (cond 
    ((equal n 0) 2)
    ((equal n 1) 1)
    (t (+ (lucas (- n 1))
          (lucas (- n 2))))))

以下是我为列表函数所写的内容。问题是(lucas n)非常慢,而且我不想在已经使用let的情况下调用助手函数。

(defun lucas-list(n)
  (cond
   ((equal n 0) (cons n nil))
   (t (let ((n1 (lucas n)) (n2 (lucas(- n 1))))
        (cons n1 (lucas-list n2))))))

我正在努力实现的目标:

(lucas-list 3) => '(4 3 1 2))

任何建议/帮助都将不胜感激

斐波那契数的(伪)线性时间算法可以很容易地扩展到Lucas数:

(define (lucas n)
  (let loop ((a 2) (b 1) (n n))
    (if (= n 0)
      a
      (loop b (+ a b) (- n 1)))))

这可以映射到整数上以获得所需的结果:

> (map lucas '(0 1 2 3 4 5))
(2 1 3 4 7 11)
> (reverse (map lucas '(0 1 2 3 4 5)))
(11 7 4 3 1 2)

但实际上有一种更快的方法:如果你意识到上面的算法计算Lᵢ₋₁和Lᵢ₋₂在它计算L之前ᵢ,那么将它们保存在列表中应该会节省很多时间。这就给出了:

(define (lucas n)
  (let loop ((a 2) (b 1) (n n) (l '()))
    (if (= n 0)
      l
      (loop b (+ a b) (- n 1) (cons a l)))))

行动中:

> (lucas 20)
(9349 5778 3571 2207 1364 843 521 322 199 123 76 47 29 18 11 7 4 3 1 2)

优化fibonacci类型过程的一种优雅方法是使用memoïze函数缓存之前计算的每个结果:

In Racket(使用哈希表;通用,可扩展性很好)

(define (memoize fn)
  (let ((cache (make-hash)))
    (lambda arg (hash-ref! cache arg (lambda () (apply fn arg))))))

在R6RS方案中(效率较低,通用性较差,但仍非常适合此目的)

(define (memoize proc)
  (let ([cache '()])
    (lambda (x)
      (cond
        [(assq x cache) => cdr]
        [else (let ([ans (proc x)])
                (set! cache (cons (cons x ans) cache))
                ans)])))) 

应用于lucas过程(这就像Python装饰器一样工作):

(define lucas
  (memoize
   (lambda (n)
     (cond
       ((= n 0) 2)
       ((= n 1) 1)
       (else   (+ (lucas (- n 1)) (lucas (- n 2))))))))

列表过程利用了使用累加器反转结果的事实,变成了:

(define (lucas-list n)
  (let loop ((i 0) (res null))
    (if (= i n)
        res
        (loop (+ i 1) (cons (lucas i) res)))))

测试:

(display (lucas-list 20))
=> {9349 5778 3571 2207 1364 843 521 322 199 123 76 47 29 18 11 7 4 3 1 2}

怎么样:

(defun lucas-list (n)
  (if (equal n 0)
      '()
      (cons (lucas n) (lucas-list (- n 1)))))
(defun lucas-list-decreasing (n &aux (table (make-hash-table)))
  (labels ((lucas-int (n)
              (or (gethash n table)
                  (setf (gethash n table)
                        (cond ((equal n 0) 2)
                              ((equal n 1) 1)
                              (t (+ (lucas-int (- n 1))
                                    (lucas-int (- n 2)))))))))
    (lucas-int n)
    (loop for i downfrom (1- n) downto 0
          collect (gethash i table))))

或者:

(defun lucas (n &aux (table (make-hash-table)))
  (labels ((lucas-int (n)
             (or (gethash n table)
                 (setf (gethash n table)
                       (cond ((equal n 0) 2)
                             ((equal n 1) 1)
                             (t (+ (lucas-int (- n 1))
                                   (lucas-int (- n 2)))))))))
    (values (lucas-int n)
            table)))
(defun lucas-list-decreasing (n)
  (multiple-value-bind (value table)
      (lucas n)
    (declare (ignore value))
    (loop for i downfrom (1- n) downto 0
          collect (gethash i table))))

最新更新