2

I was asked in an internship interview to do a R5RS program that creates a function, let's say two-subsets. This function has to return #t if the list L contains two subsets with equal sums of elements and with equal numbers of elements, otherwise it returns #f. It takes in entry the list L (only positive numbers) and some parameters (that I judge useful. There is no conditions on the number of parameters) all equal to 0 at the beginning.

The requirements as I still remember were as follow: - Do not define other functions and call them inside the "two-subsets" function. - It can only use the following constructs: null?, cond, car, cdr, else, + ,=, not, and, #t, #f, two-subsets (itself for recursive call), the names of the parameters, such as list, sum, ...etc, numeric constants and parentheses.

There were some given examples on the results that we are supposed to have, let's say:

(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. 

I started by writing the signature that it looks to me it should be something like this:

(define two-subsets (lambda (L m n ... other parameters)
                    (cond

The problem is really complicated and it's complexity is obviously more than O(n), I read on it on https://en.wikipedia.org/wiki/Partition_problem .

I tried to start by defining the algorithm first before coding it. I thought about taking as parameters: sum of the list L so in my conditions I'll iterate only on the combinations which sum is <= sum(L)/2. By doing that I can reduce a little bit the complexity of the problem, but still I couldn't figure out how to do it.

It looks like an interesting problem and I really want to know more about it.

Benz
  • 289
  • 4
  • 15
  • This isn't quite the partition problem since you don't state that the subsets need to partition the set. Given this, I think you also need to specify that the subsets must not be empty, or it is always true since {}, {} are two such subsets. –  Apr 26 '17 at 16:57

1 Answers1

2

Here is a version which does not depend on the numbers being all positive. I am reasonably sure that, by knowing they are, you can do much better than this.

Note this assumes that:

  • the partition does not need to be exhaustive;
  • but the sets must not be empty.

I'd be very interested to see a version which relies on the elements of the list being +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)]))
  • Thanks it is working. What is the difference when adding Lambda? – Benz Apr 26 '17 at 22:01
  • 1
    @Benz `(define (x ...) ...)` is shorthand for `(define x (lambda (...) ...)` –  Apr 26 '17 at 22:25
  • @tfb I do not think that having all numbers positive helps. We can go from the original problem to the "positive" problem by adding a sufficiently large constant. That does not change the conditions when the function should return true/false. Computing a sufficiently large constant is O(n). So, whatever the efficiency of the algorithm for positive numbers, the algorithm for all numbers will have the same efficiency. – Andrei May 08 '17 at 19:01