tags:

views:

759

answers:

2

I have an array of "Range" objects with properties "Offset" and "Length", as shown below. Assume that it'll be sorted by "Offset" ascending.

Range array contains:

Offset        Length     Index
-------       -------    -------
100           10         0
110           2          1 
112           5          2
117           3          3
300           5          4
305           5          5 
400           5          6
405           10         7
415           2          8
417           4          9
421           7          10
428           1          11 
429           6          12  
500           4          13
504           9          14

The contiguous subsequences in this case would be:

Sequence #1 indices: 0, 1, 2, 3
Sequence #2 indices: 4, 5
Sequence #3 indices: 6, 7, 8, 9, 10, 11, 12  <-- (longest!!)
Sequence #4 indices: 13, 14

Assume that there will only be one longest sequence. Iterating through the items, i thought to create a new array for each contiguous sequence and return the biggest array, but that seem sub-optimal. Is there a better way to do this? I'm implementing in C# 2.0. The function should either return an array containing the elements of the longest subsequence, or the starting and ending indices of the longest subsequence in the original array.

Thanks everyone for taking a stab at this.

+3  A: 

This problem is not related to contiguous subsequence problem etc. but is a simple problem which can be solved in O(n) time. It seems to me that the "strings" represented by the array are not overlapping, so there is a very simple algorithm: put left index finger on the first row, and then run the right index finger downwards as long as you are within a contiguous sequence. When the sequence ends, store the length and the starting location. Then repeat this. Whenever you find a longer sequence than the previous record, you update the starting location.

antti.huima
You're right - the extra constraint that the sequence is not only increasing but contiguously increasing makes it much simpler. Deleted my answer.
Tyler McHenry
Thank you Antii! You are right: they are strings, and they don't overlap. One question: what if i don't have any fingers? :) *haha*
Matt
+1  A: 

A simple linear algorithm (Python, I'm sure the code can be improved):

# Your array
arr = [
  (100, 10), (110, 2), (112, 5), (117, 3), (300, 5), (305, 5), (400, 5), 
  (405, 10), (415, 2), (417, 4), (421, 7), (428, 1), (429, 6), (500, 4),
  (504, 9)
]

# Where does each element end?
ends = map(sum, arr)

s, e = 0, 0 # start and end of longest contiguous subseq
cur = 0     # length of current contiguous subseq
for j, i in enumerate(range(1, len(arr))):
    # See if current element is contiguous with the previous one
    if (arr[i][0] == ends[j]):
        cur += 1
    elif cur > 0:
        # If not, we may have found the end of a (currently) longest subseq
        if cur > (e - s):
            e = j
            s = e - cur

        cur = 0  # reset subseq length

# The longest contiguous subseq may be at the end of the array
if cur > (e - s):
    e = j + 1
    s = e - cur

# print the start and end index of the longest contiguous subseq
print(s, e)
Stephan202
Thanks Stephan. Although i don't know Python, i appreciate the attempt and voted up your answer.
Matt