Reputation: 249
I need to determine a function that for a given a sequence of integers (as an array) and that can determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
the arrays can be in range
2 ≤ sequence.length ≤ 10^5,
-10^5 ≤ sequence[i] ≤ 10^5
for example:
[1, 3, 2, 1]
we can not drop any one number in order to get increasing sequence, so the function should return False
. And True for [0, -2, 5, 6]
, [1, 1]
, [1, 3, 2]
.
I wanted to write function that deletes one number from the list and examines whether the sequence is increasing. If for all iterations we become False
than the function should return False
.
def almostIncreasingSequence(sequence):
def order(A):
n = len(A)
for i in range(n):
if A[i] >= A[i+1]:
result = True
else:
result = False
for i in range(len(s0)-1):
s_i = list(sequence)
s_i.remove(s_i.index(s_i[i]))
if order(s_i) == True:
return True
But I have got a mistake:
ValueError: list.remove(x): x not in list
What is the reason? How I can finish my code?
Upvotes: 2
Views: 1071
Reputation: 8510
as mentioned in the comments, you can use the numpy.diff for this, and thus avoiding the need to check every combination of removing 1 element from the list
import numpy
def almostIncreasingSequence(sequence):
diff = numpy.diff(sequence) < 1
return diff.sum() < 2
here first we get the difference between adjacent elements, then we ask where those differences are less than 1 and count it, and depending on the amount we get our answer.
Without numpy, we can use a similar technique
import itertools
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a,b = itertools.tee(iterable)
next(b,None)
return zip(a,b) # use itertools.izip in python 2
def almostIncreasingSequence(sequence):
return sum( a>=b for a,b in pairwise(sequence)) < 2
and this one have the advantage that use less memory than the numpy version
And here are some test for it
assert almostIncreasingSequence([0, -2, 5, 6])
assert almostIncreasingSequence([1,1])
assert almostIncreasingSequence([1,3,2])
assert almostIncreasingSequence([1,2,3,0])
assert almostIncreasingSequence([1,2,3,0,10])
assert almostIncreasingSequence([10,1,2,3,4])
assert almostIncreasingSequence([1,10,2,3,4])
assert not almostIncreasingSequence([1,2,3,0,0])
assert not almostIncreasingSequence([1,2,0,3,0,10])
assert not almostIncreasingSequence([1,2,0,3,10,0])
assert not almostIncreasingSequence([1,2,3,0,10,0])
assert not almostIncreasingSequence([10,1,2,3,10,0])
assert not almostIncreasingSequence([1, 3, 2, 1])
in response to the comments, here is an early stop version
def almostIncreasingSequence(sequence):
diff = 0
for a,b in pairwise(sequence):
if a>=b:
diff += 1
if diff >= 2:
return False
return diff < 2
and an accompanying test
assert not almostIncreasingSequence(itertools.chain([1, 3, 2, 1],range(10**100))) # use xrange with python 2
which will take ages with any of the other version
Upvotes: 3
Reputation: 3349
def almostIncreasingSequence(sequence):
for i in range(len(sequence)-1):
s_i = list(sequence)
# Remove the item by index
del s_i[i]
if order(s_i) == True:
return True
# Need to return false at the end if we never find a solution
return False
# You should have tested this function separately first.
# It did not work, so obviously almostIncreasingSequence wouldn't work.
def order(A):
n = len(A)
# Should have been n-1, not n, because you compare against n+1
# which doesn't exist when you hit the tail
for i in range(n - 1):
if A[i] > A[i + 1]:
# Need to actually return the value, not just set it to a variable
return False
# Only tell us it's in order if ALL the values don't fail
return True
print almostIncreasingSequence([1, 3, 2])
Upvotes: 1