R5RS中的号码分区

时间:2017-04-26 15:07:37

标签: lisp racket r5rs

我在实习面试中被要求做一个创建一个函数的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的组合。通过这样做,我可以减少问题的复杂性,但我仍然无法弄清楚如何做到这一点。

这看起来像一个有趣的问题,我真的想了解更多。

1 个答案:

答案 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)]))