3

I'm trying to write an algorithm that will return True/False whether a contiguous sequence in a sorted array that contains only positive integers, can sum up to N.

For example:

Array = {  1, 2, 3, 4 };
6 is good! 1 + 2 + 3 = 6
8 is not good! 1 + 3 + 4 = 8, but it's not contiguous, since we skipped the 2.

This is what I have tried to do:

int[] arr = ...;
int headIndex = 1, tailIndex = 0, sum = arr[0];

while (sum != n)
{
    if (sum < n)
    {
        sum += arr[headIndex++];
    }

    if (sum > n)
    {
        sum -= arr[tailIndex++];
    }
}

return sum == n;

Obviously the above does not work (In some cases it might get stuck in an infinite loop). Any suggestions?

One thing I haven't mentioned earlier, and is very important- the algorithm's complexity must be low as possible.

Novak
  • 2,760
  • 9
  • 42
  • 63
  • `sum -= arr[tailIndex--];` looks wrong to me. Have you tried `sum -= arr[tailIndex++];`? – murat May 14 '13 at 21:21
  • @murat You are absolutely right, my bad. But still, it will get stuck in an infinite loop. – Novak May 14 '13 at 21:21
  • Obviously, you don't need to examine elements in the array that are larger than your target N. Otherwise, it probably depends on the statistics of the data as to whether it's better to start at the low end or the high end, or maybe even somewhere in the middle. – Hot Licks May 14 '13 at 21:27
  • And, obviously, you need (in the general case) to have a check for headIndex exceeding the array bound. – Hot Licks May 14 '13 at 21:28

5 Answers5

8

This is just a sketch:

  1. Loop from left to right, find the largest k that n1 + ... + nk <= target, set sum = n1 + ... + nk. If the array sum is smaller than target, then return false.
  2. If sum == target, we are done. If not, then any subarray S that sum to target will have S.length < k, and will begin from an element that is larger than the first one. So we kick out the first from the sum: sum -= n1, leftEnd++. Now we can go back to step 1, but no need to compute k from scratch.

Since the left end moves at most N times, and the right end moves at most N times, this algorithm has time complexity O(N), and constant space requirement.

zw324
  • 26,764
  • 16
  • 85
  • 118
  • 1
    It will be a little more complicated if the array contains negative as well as positive entries, but that's the right strategy. OP just added that all array entries are positive, so that's it then. – Daniel Fischer May 14 '13 at 21:19
0

Simply:

for i = 1 to n - 1:
   j = 0
   while (j < i):
      sm = 0
      for k = j to i:
        sm = sm + array[k]
      if sm == N:
        return True
      j = j + 1
return False

This works in O(n^3) time.

  • I think that this function might skip an item, and it will still return true, doesn't it? When you enter the first recursive call, and then inside it, you call the latter. – Novak May 14 '13 at 21:09
0
var i = 0;
while(i != arr.Length)
{
    var remembre = i;
    var tmp = 0;
    for(; tmp < N && i < arr.Length; ++i)
        tmp += arr[i];
    if(N == tmp)
        return true;
    i = remembre + 1;
}
return false;

I believe this should work.

Mark Segal
  • 5,427
  • 4
  • 31
  • 69
0

Here is a solution in code. It's been heavily influenced by @Ziyao Wei's sketch, which simplified my original approach (in particular, there is no need to backtrack and add the small numbers back on, only to take them off as I first thought).

public static bool HasConsecutiveSum(IList<int> list, int requiredSum)
{
    int start = 0;
    int sum = 0;

    for (int end = 0; end < list.Count; end++)
    {
        sum += list[end];

        while (sum > requiredSum)
        {
            sum -= list[start++];
            if (start > end)
            {
                return false;
            }
        }

        if (sum == requiredSum)
        {
            return true;
        }        
    }

    return false;
}
Matthew Strawbridge
  • 19,940
  • 10
  • 72
  • 93
0

I think the most optimal algorithm works with a window that moves over the list. The value of the window (WV) is the sum of the elements that fall within the window. If WV is less then N, move the head and add the new value that fits within the window to WV, if the value is bigger then N, move the tail one up and subtract the value that falls of the window from WV. The algorithm stops when WV equals N, or the tail moves beyond the head, or the head is at the end of the list, and WV is still to low.

This would run in linear time: every element in the list is once added and once subtracted at most.

Written down in some code to illustrate the idea (python alike), but not tested

WV = list[0]
L = len(list)
tail = 0
head = 0

while WV != N
  if WV < N
    head += 1
    if head < L
       WV += list[head]
    else
      return false // beyond end of list
  elif WV > N
    if tail < head
       WV -= list[tail]
       tail += 1
    else
      return false // single element bigger then N, and list is sorted

return true
Jan Boonen
  • 95
  • 7