将递归问题代码从Python转换为CommonLisp

我正在尝试将用 Python 编写的递归问题(此处的第 4 个问题,请参阅其 repo 页面了解详细信息)转换为(通用)Lisp

这是我为了可读性稍微编辑过的 Python 代码:

def coin(target,coins,res):
    # Default output to target
    min_coins = target
    # Base Case
    if target in coins:
        res[target] = 1
        return 1
    # Return a known result if it happens to be greater than 1
    elif res[target] > 0:
        return res[target]
    else:
        # for every coin value that is <= than target
        for i in [c for c in coins if c <= target]:
            num_coins = 1 + coin(target-i,coins,res)
            # Reset Minimum if we have a new minimum
            if num_coins < min_coins:
                min_coins = num_coins
                res[target] = min_coins
    return min_coins

target = 14
coins = [1,3,5]
res = [0]*(target+1)
print(coin(target,coins,res))
# => returns 4  ( 1 x 1, 1 x 3, 2 x 5)

这是我写的 Lisp 代码:

(defun coin (target coins res)
  (let ((min_coins target))  
    (if (some (lambda (x) (= target x)) coins)
        (progn
          (setf (aref res target) 1)
          1)
      (if (> (aref res target) 0)
          (aref res target)
        (dolist (i (remove-if-not (lambda (x) (<= x target)) coins))
          (let ((num_coins (1+ (coin (- target i) coins res))))
            (when (< num_coins min_coins)
              (setf min_coins num_coins)
              (setf (aref res target) min_coins))
            min_coins))))))

(coin 14 '(1 3 5) (make-array 15 :initial-element 0) )

当它被执行时,它会因为这个错误而停止:

The value
  NIL
is not of type
  NUMBER
The value
  NIL
is not of type
  NUMBER

如何安排它才能正确运行?

更新:

经过(trace coin)这里的输出:

回答

正确性

你的代码失败,因为你的dolist回报nil

你需要更换

(dolist (i (remove-if-not (lambda (x) (<= x target)) coins)) ...)

(dolist (i (remove-if-not (lambda (x) (<= x target)) coins) min_coins) ...)

效率

您在 Python 中使用[]infor循环和在 Lisp 中使用remove-if-notin创建免费列表dolist。众所周知的“足够聪明的编译器”应该能够消除它,但 Python 3 不够聪明,SBCL 也不够聪明。

风格

代码可读性很重要。我建议修改您的代码:

def coin(target,coins,res):
    # Default output to target
    # Base Case
    if target in coins:
        res[target] = 1
        return 1
    # Return a known result if it happens to be greater than 1
    if res[target] > 0:
        return res[target]
    # for every coin value that is <= than target
    min_coins = target
    for i in target:
        if i <= target:
            num_coins = 1 + coin(target-i,coins,res)
            # Reset Minimum if we have a new minimum
            if num_coins < min_coins:
                min_coins = num_coins
                res[target] = min_coins
    return min_coins
def coin(target,coins,res):
    # Default output to target
    # Base Case
    if target in coins:
        res[target] = 1
        return 1
    # Return a known result if it happens to be greater than 1
    if res[target] > 0:
        return res[target]
    # for every coin value that is <= than target
    min_coins = target
    for i in target:
        if i <= target:
            num_coins = 1 + coin(target-i,coins,res)
            # Reset Minimum if we have a new minimum
            if num_coins < min_coins:
                min_coins = num_coins
                res[target] = min_coins
    return min_coins


以上是将递归问题代码从Python转换为CommonLisp的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>