【问题标题】:Number Partitioning in R5RSR5RS 中的数字分区
【发布时间】:2017-09-24 02:00:48
【问题描述】:

我在一次实习面试中被要求做一个 R5RS 程序来创建一个函数,比如说两个子集。如果列表 L 包含两个元素总和相等且元素数量相等的子集,则此函数必须返回 #t,否则返回 #f。它在入口处接受列表 L(只有正数)和一些参数(我认为有用。参数数量没有条件)在开始时都等于 0。

我还记得的要求如下: - 不要定义其他函数并在“双子集”函数中调用它们。 - 它只能使用以下构造:null?、cond、car、cdr、else、+、=、not、and、#t、#f、二子集(本身用于递归调用)、参数名称、例如列表、总和、...等、数字常量和括号。

有一些关于我们应该得到的结果的示例,比如说:

(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 的总和作为参数,因此在我的条件下,我将仅对总和

这看起来是一个有趣的问题,我真的很想知道更多。

【问题讨论】:

  • 这不是分区问题,因为您没有声明子集需要对集合进行分区。鉴于此,我认为您还需要指定子集不能为空,否则始终为真,因为 {}、{} 是两个这样的子集。

标签: lisp racket r5rs


【解决方案1】:

这是一个不依赖于数字都是正数的版本。我有理由相信,通过了解它们,您可以做得比这更好。

注意这里假设:

  • 分区不必是详尽的;
  • 但集合不能为空。

我很想看到一个依赖列表元素为 +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)]))

【讨论】:

  • 感谢它正在工作。添加 Lambda 有什么区别?
  • @Benz (define (x ...) ...)(define x (lambda (...) ...) 的简写
  • @tfb 我认为所有数字都为正数并没有帮助。通过添加一个足够大的常数,我们可以从原始问题转到“正”问题。这不会改变函数应该返回真/假的条件。计算一个足够大的常数是 O(n)。因此,无论正数算法的效率如何,所有数的算法都将具有相同的效率。
猜你喜欢
  • 1970-01-01
  • 2011-10-27
  • 2011-07-28
  • 1970-01-01
  • 1970-01-01
  • 2012-10-28
  • 1970-01-01
  • 2023-03-30
  • 1970-01-01
相关资源
最近更新 更多