1

Given an array, the output array consecutive elements where total sum is 0.

Eg:

For input [2, 3, -3, 4, -4, 5, 6, -6, -5, 10],

Output is [3, -3, 4, -4, 5, 6, -6, -5]

I just can't find an optimal solution.

Clarification 1: For any element in the output subarray, there should a subset in the subarray which adds with the element to zero.

Eg: For -5, either one of subsets {[-2, -3], [-1, -4], [-5], ....} should be present in output subarray.

Clarification 2: Output subarray should be all consecutive elements.

Sreejith Ramakrishnan
  • 1,332
  • 2
  • 13
  • 22
  • define **optimal**... you forgot to do that. – Marcus Müller Sep 20 '15 at 15:39
  • Also, what language? – AJMansfield Sep 20 '15 at 15:41
  • fewest count of excluded elements? Would that be equivalent to taking the sum, then finding the fewest elements which add up to that sum? – Kenny Ostrom Sep 20 '15 at 15:41
  • @AJMansfield: OP is asking for algo, not impl – Marcus Müller Sep 20 '15 at 15:41
  • 3
    Hint: good answers are given to those that, after asking a question, spend the next five minutes or so waiting for comments and reacting to them... – Marcus Müller Sep 20 '15 at 15:42
  • So, you want to remove all x for which -x is not in the array? – AJMansfield Sep 20 '15 at 15:43
  • possible duplicate of [Zero sum SubArray](http://stackoverflow.com/questions/5534063/zero-sum-subarray) – n. m. could be an AI Sep 20 '15 at 15:47
  • I missed the word "consecutive" oops. So optimal would be longest sequence. Seems like the simple brute force is the best algorithm, then. – Kenny Ostrom Sep 20 '15 at 15:47
  • @AJMansfield Not limited to that. Say you have 3 and -1, -2, those add to zero and should be considered. – Sreejith Ramakrishnan Sep 20 '15 at 15:55
  • @SreejithRamakrishnan Your example does not support that, You include -4, -6, and 10, but 10 is not in the output. – AJMansfield Sep 20 '15 at 15:56
  • To clarify: as I presently understand it, you wish to remove all elements for which no subset of other elements will sum with it to 0. Is that correct? – AJMansfield Sep 20 '15 at 15:57
  • @AJMansfield Selecting -4 & -6 to cover 10 would rid 6 of a match. This would break subarray (not consecutive). – Sreejith Ramakrishnan Sep 20 '15 at 16:03
  • @AJMansfield Yes. Exactly like that. Remove all elements for which no other subset of elements will sum with it to 0. – Sreejith Ramakrishnan Sep 20 '15 at 16:05
  • @SreejithRamakrishnan Be careful about "subset" vs "subsequence"; If 10 is not in the output, then it can't be what I said. An interpretation consistent with it though is that you want to remove any element such that no subsequence containing it sums to 0. – AJMansfield Sep 20 '15 at 16:07
  • 1
    Your "clarifications" do not clarify anything, because of the way you misuse the terminology. You said you can't find an "optimal" way of doing it, but if you just post the non-optimal algorithm you wrote, we will be able to understand exactly what you are asking for. – AJMansfield Sep 20 '15 at 17:07
  • 1
    Please make up your mind. Do you want `[3, -3, 4, -4, 5, 6, -6, -5]` or `{[-2, -3], [-1, -4], [-5], ....}`? – n. m. could be an AI Sep 20 '15 at 19:02
  • @n.m You misread. What I meant was, for any number n, there should a subset of numbers in the output array which when summed with n, would give 0. – Sreejith Ramakrishnan Sep 21 '15 at 06:06
  • It is of course entirely impossible to even check effectively that thete is such a subset, see subset sum problem. – n. m. could be an AI Sep 21 '15 at 06:43
  • @n.m. Assuming all elements in the output array have a negative sum counterpart, I think it's impossible to have any such counterpart be a subset with more than one element. If there were such a subset, it would mean that all the numbers in this subset must also have counterparts, but in order for the total output sum to be zero, any number in the output array can only be part of *one* part-counterpart pair, and this would invalidate this constraint. – גלעד ברקן Sep 21 '15 at 16:48
  • @גלעדברקן Counterexample: 1,1,1,-1,-1,-1,3. – n. m. could be an AI Sep 21 '15 at 17:01
  • @n.m. OP states in the question "For any element in the output subarray, there should a subset in the subarray which adds with the element to zero." As well as, "the output array consecutive elements where total sum is 0." Abd in the comment to you, "for any number n, there should a subset of numbers in the output array which when summed with n, would give 0." – גלעד ברקן Sep 21 '15 at 17:02
  • @n.m. Total sum in your counter example is `1+1+1-1-1-1+3 = 3`. OP stated "the output array consecutive elements where total sum is 0". – גלעד ברקן Sep 21 '15 at 17:55
  • @גלעדברקן apparently I can't count to zero. 1+1+1-1-1-1-1-1-1+3 should work. – n. m. could be an AI Sep 21 '15 at 18:02
  • @n.m. I see, thanks! – גלעד ברקן Sep 22 '15 at 15:22
  • @SreejithRamakrishnan When you say that you would like, "for any number `n`...a subset of numbers in the output array which [gives zero when summed with `n`]," do you mean a contiguous subset? In other words would `1-1+1-1+1-1-1+3-1-1` be valid? (notice that the counterpart for 3 is not contiguous) – גלעד ברקן Sep 22 '15 at 23:04
  • @גלעדברקן Yes, contiguous. I guess if not contiguous, it would be an rSum problem, wouldn't it? – Sreejith Ramakrishnan Sep 23 '15 at 08:25

4 Answers4

2

Here is a python solution that runs in O(n³):

def conSumZero(input):
    take = [False] * len(input)

    for i in range(len(input)):
        for j in range(i+1, len(input)):
            if sum(input[i:j]) == 0:
                for k in range(i, j):
                    take[k] = True;

    return numpy.where(take, input)

EDIT: Now more efficient! (Not sure if it's quite O(n²); will update once I finish calculating the complexity.)

def conSumZero(input):
    take = [False] * len(input)
    cs = numpy.cumsum(input)
    cs.insert(0,0)

    for i in range(len(input)):
        for j in range(i+1, len(input)):
            if cs[j] - cs[i] == 0:
                for k in range(i, j):
                    take[k] = True;

    return numpy.where(take, input)

The difference here is that I precompute the partial sums of the sequence, and use them to calculate subsequence sums - since sum(a[i:j]) = sum(a[0:j]) - sum(a[0:i]) - rather than iterating each time.

AJMansfield
  • 4,039
  • 3
  • 29
  • 50
  • I like it, but shouldn't you start j and the end and work backwards, so you check the largest solutions first? That way you can terminate the search immediately upon finding a solution. Just on visual inspection, it looks like you will find every possible solution, mark them for "take", and then merge them all together. But what if two different solutions get merged to an output that adds up to a non-zero value? – Kenny Ostrom Sep 21 '15 at 18:48
  • check this against [1, 2, 3, -6, 1, 2] – Kenny Ostrom Sep 21 '15 at 18:50
  • @KennyOstrom It doesn't matter what order I check them in for this algorithm. True, if I started with the large ones first, I could probably do some early exiting when checking the smaller ones, but I don't feel like writing it right now. What this does is mark each element that is part of some zero-sum subsequence, and then take all the marked elements. If I mark an element twice, it still only gets included once. – AJMansfield Sep 21 '15 at 18:52
  • @KennyOstrom In the case of [1 2 3 -6 1 2] it would output [1 2 3 -6 1 2], since [1 2 3 -6] sums to 0, and [3 -6 1 2] sums to 0. Those subsequences include every element, therefore every element gets marked and subsequently included in the output. – AJMansfield Sep 21 '15 at 18:54
  • But the output does not add up to 0, so you understand my concern. You are going by the revised clarification where every element has a subset that sums with it to 0, then, and disregarding the original constraint? – Kenny Ostrom Sep 21 '15 at 19:00
  • I also wonder about the "consecutive" constraint. If you find a largest solution and exit immediately, you know they are consecutive, but if you find all solutions, then you get an output which was not consecutive in the original input. [2, -2, 999, -3, 3] -> [2, -2, -3, 3] – Kenny Ostrom Sep 21 '15 at 19:03
  • @KennyOstrom That's not how I understood the question; the question plus the comments on it leads me to believe this is the correct interpretation of the problem. – AJMansfield Sep 21 '15 at 20:03
  • @KennyOstrom Actually, reading more recent comments and edits, I think you are right, this is not the correct interpretation. – AJMansfield Sep 21 '15 at 20:06
1

Why not just hash the incremental sum totals and update their indexes as you traverse the array, the winner being the one with largest index range. O(n) time complexity (assuming average hash table complexity).

       [2, 3, -3, 4, -4, 5, 6, -6, -5, 10]
sum  0  2  5   2  6   2  7  13  7   2  12

The winner is 2, indexed 1 to 8!

To also guarantee an exact counterpart contiguous-subarray for each number in the output array, I don't yet see a way around checking/hashing all the sum subsequences in the candidate subarrays, which would raise the time complexity to O(n^2).

גלעד ברקן
  • 23,602
  • 3
  • 25
  • 61
  • When you compute a partial sum, you look up whether that partial sum has happened before, and that gives you the start and end (and therefore length) of a zero sum subset. Store the longest. And you're asserting O(1) for the lookup using a hash table (dict). Okay, I like it. Maybe include 0 as the first sum so you can handle an input where the first entry is 0? – Kenny Ostrom Sep 21 '15 at 19:26
  • @KennyOstrom thanks for commenting. I think I assumed zero for the starting sum; anyway, I added it. – גלעד ברקן Sep 21 '15 at 19:58
  • If the output sum is 0, then each item has an exact counterpart consisting of all the rest of the output array. – Kenny Ostrom Sep 21 '15 at 20:39
  • @KennyOstrom not sure what you mean by, "each item has an exact counterpart consisting of all the rest of the output array." Can you give a simple example? – גלעד ברקן Sep 21 '15 at 22:01
  • The output is a list of numbers which add up to 0, e.g. [50, -5, -10, -15, -20] and you want an algorithm to determine if for any element in the list, there is a subset of other elements which add up to that element. You were worried about the time complexity of computing that. I said it is O(0) because it is already known, so you don't have to compute it. – Kenny Ostrom Sep 22 '15 at 17:20
  • Take any element, say 50. The "exact counterpart subarray" is all the other elements, [-5, -10, -15, -20]. The phrase "exact counterpart subarray" comes from your edit to the answer, above. – Kenny Ostrom Sep 22 '15 at 17:21
  • @KennyOstrom I think the OP wanted the counterpart as a contiguous subarray. Your explanation, while correct, would not satisfy that constraint. – גלעד ברקן Sep 22 '15 at 22:54
0

Based on the example, I assumed that you wanted to find only the ones where 2 values together added up to 0, if you want to include ones that add up to 0 if you add more of them together (like 5 + -2 + -3), then you would need to clarify your parameters a bit more.

The implementation is different based on language, but here is a javascript example that shows the algorithm, which you can implement in any language:

var inputArray = [2, 3, -3, 4, -4, 5, 6, -6, -5, 10];
var ouputArray = [];

for (var i=0;i<inputArray.length;i++){
    var num1 = inputArray[i];

    for (var x=0;x<inputArray.length;x++){
        var num2 = inputArray[x];
        var sumVal = num1+num2;
        if (sumVal == 0){
            outputArray.push(num1);
            outputArray.push(num2);

        }

    }
}
  • I'm pretty sure you can't just expect to find only +x and -x pairs. You'll need to handle [..., 2, 2, -4, ...] – Kenny Ostrom Sep 20 '15 at 15:46
  • This solution is not correct. If the number's pair is not adjacent, this will rearrange the ordering, and it will output each number twice. – AJMansfield Sep 20 '15 at 15:46
  • 1
    @KennyOstrom The example contained -4. -6, and 10, but 10 was not output. – AJMansfield Sep 20 '15 at 15:47
  • I agree, this doesn't handle more than 2 values equalling 0. I added that caveat in an edit and asked for clarification. Yes, this would list the same value more than once and would also not honor the original sort order. If those are important features, it can be re-worked, I just kept it simple since there was not a very clear definition of what is desired. – CodeMonkeyArtist Sep 20 '15 at 15:50
  • I also missed the word consecutive above. Could the OP clarify exactly what is desired, before I put any effort into reworking it for more adding more than 2 values, consecutive only, no duplicates, sort order, etc... – CodeMonkeyArtist Sep 20 '15 at 15:52
0

Is this the problem you are trying to solve?

Given a sequence , find maximizing such that

If so, here is the algorithm for solving it:

let $U$ be a set of contiguous integers
for each contiguous $S\in\Bbb Z^+_{\le n}$
    for each $\T in \wp\left([i,j)\right)$
      if $\sum_{n\in T}a_n = 0$
        if $\left|S\right| < \left|U\left$
          $S \to u$

return $U$

(Will update with full latex once I get the chance.)

Community
  • 1
  • 1
AJMansfield
  • 4,039
  • 3
  • 29
  • 50