我只有一个列表,我需要将每个值与每个其他值进行比较,直到我到达列表的末尾,或者找到一个求和为0的数字。我也受到限制,我可以使用什么构造(null?、car、cdr、cons、on )。我不能使用嵌套的COND或任何变量。我不知道该怎么做。
我可以用cdr递归地遍历整个列表,但它只是比较列表中的相邻数。例如,由于5-5=0,所以我的测试列表应该是真的,但我不知道如何获得比较5和-5的算法,因为每次迭代时,car都会改变。
到目前为止,我已经:
(define add (lambda (lst)
(cond
;Null check
((null? (cdr lst)) #f)
;Adds car and car of cdr to check for 0.
((= 0 (+ (car lst) (car(cdr lst)))) #t)
;Recursive portion
((car lst) (sum (cdr lst))) **Not having any luck with this part.
)))
(sum '(5 6 -5))
发布于 2022-11-17 06:13:19
使用累加器存储已检查的元素
一种解决方案是编写一个带有三个参数的助手函数:要检查的候选值、要检查的列表和以前检查过的值列表。主函数将在检查输入列表中至少有两个值开始后调用助手函数。
如果要检查的列表为空,且选中的值列表中仅剩一个选中的值,则不存在零和对。
否则,如果要检查的列表为空,则候选值没有与任何其他值之和为零,因此可以丢弃它,并且可以对照该列表的其余部分检查以前检查过的值列表中的第一个值。
否则,如果候选值和要检查的值列表的第一个元素之和为零,则会找到一个零和对。
否则,要检查的值列表的第一个元素与候选值之和不等于零,因此可以将其移到选中的值列表中,并且可以对照要检查的列表的其余部分对候选元素进行检查。
这里有一个用通用Lisp编写的解决方案。您将不得不做一些工作来将它转换为Scheme,但这不会有太大的麻烦,因为它已经在一个相当阴谋诡计的风格。可能需要进行一些小的修改,才能准确地得到您所期望的作业行为,但我认为所使用的原则是明确的。
(defun zero-summands-helper (candidate xs checked)
(cond ((and (null xs) (null (cdr checked))) '())
((null xs)
(zero-summands-helper (car checked) (cdr checked) '()))
((zerop (+ candidate (car xs)))
(cons candidate (car xs)))
(t
(zero-summands-helper candidate (cdr xs) (cons (car xs) checked)))))
(defun zero-summands (xs)
(cond ((null xs) '())
((null (cdr xs)) '())
(t
(zero-summands-helper (car xs) (cdr xs) '()))))
下面是一些交互示例:
CL-USER> (zero-summands '(-1 1))
(-1 . 1)
CL-USER> (zero-summands '(1 1))
NIL
CL-USER> (zero-summands '(5 6 -5))
(5 . -5)
CL-USER> (zero-summands '(1 2 3 4 -2 5 6))
(2 . -2)
Common有一个trace
特性,它对于查看递归调用非常有用。在这里跟踪zero-summands-helper
,这可能有助于理解上面的解决方案是如何工作的:
CL-USER> (trace zero-summands-helper)
(ZERO-SUMMANDS-HELPER)
CL-USER> (zero-summands '(-1 1))
0: (ZERO-SUMMANDS-HELPER -1 (1) NIL)
0: ZERO-SUMMANDS-HELPER returned (-1 . 1)
(-1 . 1)
CL-USER> (zero-summands '(5 6 -5))
0: (ZERO-SUMMANDS-HELPER 5 (6 -5) NIL)
1: (ZERO-SUMMANDS-HELPER 5 (-5) (6))
1: ZERO-SUMMANDS-HELPER returned (5 . -5)
0: ZERO-SUMMANDS-HELPER returned (5 . -5)
(5 . -5)
CL-USER> (zero-summands '(1 2 3 -2))
0: (ZERO-SUMMANDS-HELPER 1 (2 3 -2) NIL)
1: (ZERO-SUMMANDS-HELPER 1 (3 -2) (2))
2: (ZERO-SUMMANDS-HELPER 1 (-2) (3 2))
3: (ZERO-SUMMANDS-HELPER 1 NIL (-2 3 2))
4: (ZERO-SUMMANDS-HELPER -2 (3 2) NIL)
5: (ZERO-SUMMANDS-HELPER -2 (2) (3))
5: ZERO-SUMMANDS-HELPER returned (-2 . 2)
4: ZERO-SUMMANDS-HELPER returned (-2 . 2)
3: ZERO-SUMMANDS-HELPER returned (-2 . 2)
2: ZERO-SUMMANDS-HELPER returned (-2 . 2)
1: ZERO-SUMMANDS-HELPER returned (-2 . 2)
0: ZERO-SUMMANDS-HELPER returned (-2 . 2)
(-2 . 2)
使用帮助函数检查第一个元素
另一种方法是编写一个助手函数,检查输入列表的第一个元素在列表的其余部分中是否存在加性逆。
只有当输入列表至少包含两个元素时,主函数才会调用助手函数。然后,主函数将使用第一个元素和列表的其余部分调用helper函数,迭代该列表,并返回一对或空列表。如果返回了一对,我们就完成了,这对可以返回到调用堆栈中。否则,输入的第一个元素在列表的其余部分中没有加性逆,因此可以在输入列表的cdr
上调用主函数,再次检查是否还剩下至少两个元素,然后根据简化列表的第一个元素检查加性逆。
;;; Returns a pair containing X and a member of XS summing to 0 if one exists,
;;; NIL otherwise.
(defun first-zero-summand (x xs)
(cond ((null xs) '())
((zerop (+ x (car xs))) (cons x (car xs)))
(t
(first-zero-summand x (cdr xs)))))
;;; Returns a pair of elements of XS containing the first element which has
;;; an additive inverse together with its inverse if such a pair exists,
;;; or NIL otherwise.
(defun some-zero-summand (xs)
(if (or (null xs) (null (cdr xs)))
'()
(or (first-zero-summand (car xs) (cdr xs))
(some-zero-summand (cdr xs)))))
样本交互作用:
CL-USER> (some-zero-summand '(5 6 -5))
(5 . -5)
https://stackoverflow.com/questions/74469831
复制相似问题