1

我正在制作一个带有列表和总和的程序。如果列表中的某些数字加起来等于总和,则返回 true。否则,返回假。它似乎适用于某些情况,但不适用于其他情况。例如,

如果我输入这个:

(numlist-sum '(5 9) 9)

它应该返回 true,因为其中一个数字 (9) 等于总和 (9)。但是,由于某种原因,它返回错误。

我无法弄清楚问题是什么。请帮忙?

(define (numlist-sum? ls sum)
  (if (null? ls) #t
    (if (and (null? (cdr ls)) (equal? (car ls) sum)) #t
      (if (equal? (car ls) sum) #t
          (if (equal? (cdr ls) sum) #t
              (if (equal? (apply + (car ls) (cdr ls)) sum) #t
                  #f))))))
4

2 回答 2

0

我会给你一些解决这个问题的提示(看起来像家庭作业)。首先编写一个生成列表所有可能子集的过程(例如,列表的幂集)。例如:

(powerset '(1 2 3))
=> '(() (1) (2) (3) (1 2) (1 3) (2 3) (1 2 3))

有了上面的过程(并且很容易找到算法,Google 是你最好的朋友),只需遍历每个子列表并将其值相加即可:

(apply + '(2 3))
=> 5

如果其中一个子列表的总和等于预期值,则返回#t。如果没有一个总和满足预期值,则返回#f

编辑:

我忘了提,这是一个众所周知的问题 - 它是子集和问题,可以使用动态编程有效地解决(至少,比生成幂集更有效)。但我不认为这特别是本作业的目标。

于 2013-03-28T01:14:06.043 回答
0

这是一个解决方案,它逐个检查每个元素,然后如果第一个元素不是总和,则向下递归列表。

(define (numlist-sum list sum)
  (and (not (null? list))
       (let ((head (car list)))
         (cond ((number? head)
                (or (= sum head)
                    (numlist-sum (cdr list) sum)))
               ((list? head)
                (or (= sum (apply + head))
                    (numlist-sum (cdr list) sum)))
               (else 'ill-formed-list)))))

另外,请注意,您的代码可以重写为:

(define (numlist-sum? ls sum)
  (or (null? ls)
      (if (and (null? (cdr ls)) (equal? (car ls) sum))
      (equal? (car ls) sum)
      (equal? (cdr ls) sum)
      (equal? (apply + (car ls) (cdr ls)) sum)))

我想说 '(if pred #t else ...) 的使用有点尴尬,并且隐藏了代码的真实逻辑。

于 2013-03-28T15:04:56.963 回答