我在实习面试中被要求做一个创建一个函数的R5RS程序,比方说两个子集。如果列表L包含两个具有相等元素总数和相同数量元素的子集,则此函数必须返回#t,否则返回#f。它输入列表L(仅正数)和一些参数(我认为有用。参数数量没有条件)都在开头等于0。
我仍记得的要求如下: - 不要定义其他功能并在“双子集”功能中调用它们。 - 它只能使用以下结构:null?,cond,car,cdr,else,+,=,not,和#t,#f,two-subsets(本身用于递归调用),参数名称,例如list,sum,...等,数字常量和括号。
我们应该有一些关于结果的例子,让我们说:
(two-subsets '(7 7) 0 0 0) returns #t. The two subsets are {7} and {7}.
(two-subsets '(7 7 1) 0 0) returns #t. The two subsets are {7} and {7}.
(two-subsets '(5 3 2 4) 0 0) returns #t. The two subsets are {2, 5} and {3, 4}.
(two-subsets '(1 2 3 6 9) 0 0) returns #f.
我开始编写签名,它看起来应该是这样的:
(define two-subsets (lambda (L m n ... other parameters)
(cond
问题非常复杂,而且复杂性显然超过O(n),我在https://en.wikipedia.org/wiki/Partition_problem上阅读。
我尝试在编码之前首先定义算法。我考虑将参数作为参数:列表L的总和,因此在我的条件下,我将仅迭代总和为< = sum(L)/ 2的组合。通过这样做,我可以减少问题的复杂性,但我仍然无法弄清楚如何做到这一点。
这看起来像一个有趣的问题,我真的想了解更多。
答案 0 :(得分:2)
这是一个不依赖于数字全部为正的版本。我有理由相信,通过了解它们,你可以做得更好。
请注意,这假设:
我非常有兴趣看到依赖列表元素的版本是+ ve!
(define (two-subsets? l sl sld ssd)
;; l is the list we want to partition
;; sl is how many elements we have eaten from it so far
;; sld is the length difference in the partitions
;; ssd is the sum difference in the partitions
(cond [(and (not (= sl 0))
(= sld 0)
(= ssd 0))
;; we have eaten some elements, the differences are zero
;; we are done.
#t]
[(null? l)
;; out of l, failed
#f]
;; this is where I am sure we could be clever about the set containing
;; only positive numbers, but I am too lazy to think
[(two-subsets? (cdr l)
(+ sl 1)
(+ sld 1)
(+ ssd (car l)))
;; the left-hand set worked
#t]
[(two-subsets? (cdr l)
(+ sl 1)
(- sld 1)
(- ssd (car l)))
;; the right-hand set worked
#t]
[else
;; finally drop the first element of l and try the others
(two-subsets? (cdr l) sl sld ssd)]))