0

You are given an array of positive numbers and you need to find two disjoint sub sequences with minimum difference less than or equal to n. These sub sequences may or may not be contiguous

For Example 

if array = [10,12,101,105,1000] and n = 10
Ans = [10,105] & [12,101]

If minimum difference > n then there is no solution.

Ex- array = [100, 150, 125] and n = 7

I assume this could be done using DP but I fail to derive a recurrence.

sky_coder123
  • 2,161
  • 3
  • 14
  • 15
  • This is a variant of subset sum problem and partition problem, and is most likely to be also NP-Complete, but might have a pseudo-polynomial solution using DP. – amit Feb 08 '15 at 11:21
  • What do you mean by minimum difference between sequences? – interjay Feb 08 '15 at 11:38
  • 1
    @interjay Formally, I think it comes up to the minimization problem of minimize: `|sum{x_i * a_i}|` s.t. `x_i is in {-1,0,1}`, where a_i is the i'th element in the array. -1: chosen for set A, 1: chosen for set B, 0: not chosen at all – amit Feb 08 '15 at 11:44
  • I am almost certain the problem is NP-Complete, but I am still unsure if it's strong NP-Complete (like 3-partition problem) - and there is no DP solution, or not. – amit Feb 08 '15 at 11:46
  • @amit Then you're saying that it's the difference between the sums of the two sequences? – interjay Feb 08 '15 at 11:51
  • @interjay yes from my understanding – amit Feb 08 '15 at 11:56
  • @amit golden representation :) – Lrrr Feb 08 '15 at 12:17
  • It's only weakly NP-hard. – David Eisenstat Feb 08 '15 at 12:55
  • using knapsack you will be able to a difference d < n is possible if yes then using DP you can trace back the exact partition for a specific d – advocateofnone Feb 08 '15 at 13:37
  • @sky_coder123 could you give the constraints like max value of n , the array size and each element in array ? – advocateofnone Feb 08 '15 at 13:38
  • @sasha I have not decided constraints but for my purpose n is never greater than 50. From the point of view of coding problem n can be as large as 1000. Actually this problem came to my mind because I am stuck in a real life problem relating to solution of this. – sky_coder123 Feb 08 '15 at 15:11
  • @amit Yes it might be a case of partition problem but I can't understand how is it a subset sum problem cause anyways the sum is not fixed. – sky_coder123 Feb 09 '15 at 06:19

1 Answers1

0

If the sum of all your elements is not too big (within millions), then you can do a solution similar to a knapsack problem. Your DP state is a difference between two sets, and for every element you iterate over all the differences you know so far, and update them. Since a difference cannot exceed the sum of all the elements, the complexity ends up being O(n * s) where n is the number of elements and s is their sum. You will need some kind of logic to restore the answer. For example, if all your elements are non-negative, you can just store the previous difference. Here's an example python code (I slightly modified your sample case, because for your case it finds a non-interesting answer [10], [12])

a = [5, 20, 30, 1000]
n = 7

states = {(0, False, False): None} # state is sum, hasPositive, hasNegative => prevsum, prevHasP, prevHasN
for el in a:
    newStates = {}

    for k, v in states.items():
        newStates[k] = v

    for v, hasP, hasN in states:
        if (v + el, True, hasN) not in newStates:
            newStates[(v + el, True, hasN)] = (v, hasP, hasN)
        if (v - el, hasP, True) not in newStates:
            newStates[(v - el, hasP, True)] = (v, hasP, hasN)

    states = newStates

best = None
for key, hasP, hasN in states.keys():
    if key >= -n and key <= n and hasP and hasN and (best == None or abs(best[0]) > abs(key)):
        best = (key, hasP, hasN)

if best is None: print "Impossible"
else:
    ans1 = []
    ans2 = []
    while best[1] or best[2]: # while hasPositive or hasNegative
        prev = states[best]

        delta = best[0] - prev[0]
        if delta > 0:
            ans1.append(delta)
        else:
            ans2.append(- delta)

        best = prev

    print ans1
    print ans2

As I mentioned before, it will only work if all your elements are non-negative, but it is easy to adjust the code that restores the answer to also work if the elements can be negative.

Ishamael
  • 12,583
  • 4
  • 34
  • 52
  • Answer should be [5,20] and [30] But your code fails on these – sky_coder123 Feb 11 '15 at 13:40
  • Yes, there were couple issues with the code. I fixed them in the edit. Also, old code was sometimes returning empty subsets (like `[5], []`), I addressed that as well. – Ishamael Feb 11 '15 at 19:38
  • Again it fails for `[11,101,102,103]` & `n = 7`. For `n = 7` your code outputs `[101]` and `[103]`. For `n=10` and same input your code outputs `[101,11]` and `[102]`. It seems that difference is not getting minimized and answer should not vary for different n. The most n could affect is either it has no solution for very small n and solution for appropriately large n. Do you really think that specifications of the problem make it viable enough to be solved without backtracking ? – sky_coder123 Feb 12 '15 at 06:13
  • That's because I completely missed the part about minimizing the difference. Check out the latest edit. – Ishamael Feb 12 '15 at 06:16