## Arithmetic Sequence

### February 23, 2016

Today’s exercise is an interview question from Amazon:

Determine if a list of integers forms an arithmetic sequence. For instance, the integers 1, 2, 3, 4, 5 form an arithmetic sequence because the differences between them are all the same, but the integers 1, 2, 4,8, 16 do not form an arithmetic sequence because the differences betweent them are not all the same. The input need not be sorted, so the integers 3, 2, 5, 1, 4 also form an arithmetic sequence.

Your task is to write a function that determines if a list of integers forms an arithmetic sequence. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.

I don’t think summing the steps is sufficient. First I didn’t think of it myself, then I thought it was clever, and then I began to have doubts. Here’s a counterexample.

So I have an O(n) time, O(n) space solution.

@Jussi: Oh. I missed that. Thanks for pointing it out.

In that case, I think the proper answer is to insert the integers in a hash table. Any duplicates cause a failure, in addition to the failure reported when the division fails. That still has time complexity O(

n), but raises the space complexity from O(1) to O(n).I guess that makes sense. If you can’t permit duplicates, then somehow or other you have to keep track of everything you’ve seen before, so O(1) space complexity isn’t possible.

That’s the problem with clever solutions generally: one is often much less sure that they work (and sometimes they don’t work), and often linearithmic performance is just fine. “When in doubt, use brute force.” â€”Dennis Ritchie

And yet (1 1 1 1) is an arithmetic sequence by the definition given, so the test should succeed, not fail.

Indeed. Not sure a hash table is necessary – just checking off the numbers in an array (as in Jussi’s solution) is all that is needed – and that could just be a bit array, still O(n) space but a nice small constant factor.

Maybe we should worry about the complexity of the divisions too, if we are going to do these things properly.

The size of a bit array would depend on the values in the array rather than n.

@John: I’m assuming we have found the (potential) increment value and done the divisions, so we just need n entries in the array.

O(n) solution in C

int is_arithmetic_sequence(int *list, unsigned int size)

{

int min,max,sum,i,res;

if( size<3 || !list )

{

return 0;

}

min=list[0];

max=list[0];

sum=0;

for(i=0;i<size;i++)

{

sum+=list[i];

if(list[i]max)

{

max = list[i];

}

}

res=(min+max)*size/2;

return (res==sum);

}

(@IvAn: Use the sourcecode tags, in square brackets, to keep the indentation. See link in the red bar at the top.)

Here’s a version with o(n!) worst-case time, O(n) space. It finds the least two elements, if any, in O(n) time, and then compares the permutations of the original sequence to an appropriate canonical sequence. Division by zero is succesfully avoided. Whether sorting is avoided or only implicit, I prefer not to say. Replacing the generate-and-test step with explicit sorting would give an O(n log n) time version. (This is Python. The keyword parameters to Python’s min and max are pretty cool.)

The following solution seems to work:

[codesource lang=”python”]

def is_arithmetic_seq(l):

m = min(l)

s = sum(l)

n = len(l)

# S = X_min + (X_min + diff) + (X_min + 2*diff) + …

# = N * X_min + diff * (N * (N – 1) / 2)

# so (S – X_min) mod (N * (N – 1) / 2) should be 0

return (s – n * m) % ((n * (n – 1)) / 2) == 0

if __name__ == ‘__main__’:

test_data = [[3, 2, 5, 1, 4], [1, 2, 4, 8, 16], [2, 8, 3], [1, 1, 1, 1]]

for l in test_data:

print(is_arithmetic_seq(l))

# prints:

# True

# True

# False

# False

# True

[/sourcecode]

Edit: fix source code formatting.

The following solution seems to work:

def is_arithmetic_seq_fast(l):

m = min(l)

s = sum(l)

n = len(l)

# S = X_min + (X_min + diff) + (X_min + 2*diff) + …

# = N * X_min + diff * (N * (N – 1) / 2)

# so (S – X_min) mod (N * (N – 1) / 2) should be 0

return (s – n * m) % ((n * (n – 1)) / 2) == 0

if __name__ == ‘__main__’:

test_data = [[3, 2, 5, 1, 4], [1, 2, 4, 8, 16], [2, 8, 3], [1, 1, 1, 1]]

for l in test_data:

print(is_arithmetic_seq_fast(l))

# prints:

# True

# False

# False

# True

There might a simpler solution in O(n) time

Sorry, just realized that the solution posted above take O(n log n) time because of the sort.