Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
I'm still working on mine. Wrote it like this but I can't pass the last 3 hidden tests.
def almostIncreasingSequence(sequence):
boolMe = 0
checkRep = 0
for x in range(0, len(sequence)-1):
if sequence[x]>sequence[x+1]:
boolMe = boolMe + 1
if (x!=0) & (x!=(len(sequence)-2)):
if sequence[x-1]>sequence[x+2]:
boolMe = boolMe + 1
if sequence.count(sequence[x])>1:
checkRep = checkRep + 1
if (boolMe > 1) | (checkRep > 2):
return False
return True
This was a pretty cool exercise.
I did it like this:
def almostIncreasingSequence(list):
removedIdx = [] #Indexes that need to be removed
for idx, item in enumerate(list):
tmp = [] #Indexes between current index and 0 that break the increasing order
for i in range(idx-1, -1, -1):
if list[idx]<=list[i]: #Add index to tmp if number breaks order
tmp.append(i)
if len(tmp)>1: #If more than one of the former numbers breaks order
removedIdx.append(idx) #Add current index to removedIdx
else:
if len(tmp)>0: #If only one of the former numbers breaks order
removedIdx.append(tmp[0]) #Add it to removedIdx
return len(set(removedIdx))<=1
print('\nThese should be True.')
print(almostIncreasingSequence([]))
print(almostIncreasingSequence([1]))
print(almostIncreasingSequence([1, 2]))
print(almostIncreasingSequence([1, 2, 3]))
print(almostIncreasingSequence([1, 3, 2]))
print(almostIncreasingSequence([10, 1, 2, 3, 4, 5]))
print(almostIncreasingSequence([0, -2, 5, 6]))
print(almostIncreasingSequence([1, 1]))
print(almostIncreasingSequence([1, 2, 3, 4, 3, 6]))
print(almostIncreasingSequence([1, 2, 3, 4, 99, 5, 6]))
print(almostIncreasingSequence([1, 2, 2, 3]))
print('\nThese should be False.')
print(almostIncreasingSequence([1, 3, 2, 1]))
print(almostIncreasingSequence([3, 2, 1]))
print(almostIncreasingSequence([1, 1, 1]))
print(almostIncreasingSequence([1, 1, 1, 2, 3]))
This is my Solution,
def almostIncreasingSequence(sequence):
def hasIncreasingOrder(slicedSquence, lengthOfArray):
count =0
output = True
while(count < (lengthOfArray-1)) :
if slicedSquence[count] >= slicedSquence[count+1] :
output = False
break
count = count +1
return output
count = 0
seqOutput = False
lengthOfArray = len(sequence)
while count < lengthOfArray:
newArray = sequence[:count] + sequence[count+1:]
if hasIncreasingOrder(newArray, lengthOfArray-1):
seqOutput = True
break
count = count+1
return seqOutput
The reason why your modest algorithm fails here (apart from the missing '=' in return) is, it's just counting the elements which are greater than the next one and returning a result if that count is more than 1.
What's important in this is to look at the list after removing one element at a time from it, and confirm that it is still a sorted list.
My attempt at this is really short and works for all scenario. It fails the time constraint on the last hidden test set alone in the exercise.
As the problem name suggests, I directly wanted to compare the list to its sorted version, and handle the 'almost' case later - thus having the almostIncreasingSequence. i.e.:
if sequence==sorted(sequence):
.
.
But as the problem says:
determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array (at a time).
I started visualizing the list by removing an element at a time during iteration, and check if the rest of the list is a sorted version of itself. Thus bringing me to this:
for i in range(len(sequence)):
temp=sequence.copy()
del temp[i]
if temp==sorted(temp):
.
.
It was here when I could see that if this condition is true for the full list, then we have what is required - an almostIncreasingSequence! So I completed my code this way:
def almostIncreasingSequence(sequence):
t=0
for i in range(len(sequence)):
temp=sequence.copy()
del temp[i]
if temp==sorted(temp):
t+=1
return(True if t>0 else False)
This solution still fails on lists such as [1, 1, 1, 2, 3]. As @rory-daulton noted in his comments, we need to differentiate between a 'sorted' and an 'increasingSequence' in this problem. While the test [1, 1, 1, 2, 3] is sorted, its on an increasingSequence as demanded in the problem. To handle this, following is the final code with a one line condition added to check for consecutive same numbers:
def almostIncreasingSequence(sequence):
t=0
for i in range(len(sequence)):
temp=sequence.copy()
del temp[i]
if temp==sorted(temp) and not(any(i==j for i,j in zip(sorted(temp), sorted(temp)[1:]))):
t+=1
return t>0
As this still fails the execution time limit on the last of the test (the list must be really big), I am still looking if there is a way to optimize this solution of mine.
Here's my simple solution
def almostIncreasingSequence(sequence):
removed_one = False
prev_maxval = None
maxval = None
for s in sequence:
if not maxval or s > maxval:
prev_maxval = maxval
maxval = s
elif not prev_maxval or s > prev_maxval:
if removed_one:
return False
removed_one = True
maxval = s
else:
if removed_one:
return False
removed_one = True
return True
Well, here's also my solution, I think it's a little bit cleaner than other solutions proposed here so I'll just bring it below.
What it does is it basically checks for an index in which i-th value is larger than (i+1)-th value, if it finds such an index, checks whether removing any of those two makes the list into an increasing sequence.
def almostIncreasingSequence(sequence):
def is_increasing(lst):
for idx in range(len(lst)-1):
if lst[idx] >= lst[idx + 1]:
return False
return True
for idx in range(len(sequence) - 1):
if sequence[idx] >= sequence[idx + 1]:
fixable = is_increasing([*sequence[:idx], *sequence[idx+1:]]) or is_increasing([*sequence[:idx+1], *sequence[idx+2:]])
if not fixable:
return False
return True