# Almost increasing sequence in python

## Question:

The goal of the code is to see if a sequence is almost increasing, that is, it can be made strictly increasing by removing a single element.

For example: [1, 3, 2, 3] would be strictly increasing if the element at index 1 were removed. [1, 2, 1, 2] is not almost increasing because if you removed the first ‘2’, you would get [1, 1, 2] which is not strictly increasing.

My code has to work in under 4000 ms for a sequence of length 2 <= len <= 10^5. It is likely getting caught up on very long sequences.

```
def almostIncreasingSequence(sequence):
length = len(sequence)
count = 0
for previous, next in zip(sequence[:-1],sequence[1:]):
if previous < next:
count +=1
if (length-count>2):
return False
return True
```

[1, 2, 1, 2]

[1, 2, 3, 4, 5, 3, 5, 6]

[40, 50, 60, 10, 20, 30]

would not work.. any help please

Please note that this is not a homework question, as most of you guys know, there are lots of answers to this question posted online and i was wondering if i can do it this way

## Answers:

This works:

```
import timeit
import random
def increasing_sequence_pos(sequence):
for n, (a, b) in enumerate(zip(sequence[:-1], sequence[1:])):
if a >= b:
return False, n + 1
return True, -1
def almost_increasing_sequence(sequence):
increasing, n = increasing_sequence_pos(sequence)
return (
# either it was already increasing
increasing or
# or the problem is with the last element
n == len(sequence)-1 or
((
# or the first element was the problem
n == 1
# or the element at position n was the problem
(sequence[n - 1] < sequence[n + 1]) or
# or the element at position n-1 was the problem
(sequence[n - 2] < sequence[n] < sequence[n + 1])
) and increasing_sequence_pos(sequence[n:])[0])
)
size = 1000000
# time on simple increasing series
numbers = list(range(size))
print(timeit.timeit(lambda: almost_increasing_sequence(numbers), number=1))
print(f'Result: {almost_increasing_sequence(numbers)}')
# time on single issue
numbers[random.randint(1, size)] = 0
print(timeit.timeit(lambda: almost_increasing_sequence(numbers), number=1))
print(f'Result: {almost_increasing_sequence(numbers)}')
# time on two issues issue
numbers[random.randint(1, size)] = 0
print(timeit.timeit(lambda: almost_increasing_sequence(numbers), number=1))
print(f'Result: {almost_increasing_sequence(numbers)}')
```

Note how you get varying times and the time of course depends on the hardware you’re executing on, so "4000ms" is rather silly (and very easy to achieve on modern computers, even with really, really bad code).

You’ll notice that the first is fairly steady (0.07 seconds on my workstation), while the second and third typically take a lot shorter to just a bit shorter.

Example output:

```
0.07000060000000001
Result: True
0.06909959999999998
Result: True
0.06430069999999999
Result: False
```

Note that an increasing sequence is also considered an almost increasing sequence.

```
def seqIncCheck(lst):
temp = lst[0]
for i in range(1,len(lst)):
if lst[i] > temp:
temp = lst[i]
continue
else:
return False
return True
```

Your algorithm is not even right. You are just checking if there is one or less element that is smaller that its previous. However it does not mean it is a “almost-increasing” sequence.

In brief, when you meet an element that is smaller than its previous, then sequence is “almost-increasing” if the sequence is “strictly increasing” by removing that element itself, OR by removing the previous element.

e.g.

```
1, 2, 3, [2*], 4, 5, 6
1, 2, 3, 100*, [4], 5, 6
1, 2, 3, [1], 2, 3
```

In the first 2 example, number in `[]`

is the element that is smaller than previous. However, number with `*`

is the number need to be removed to form a strictly-increasing sequence. 3rd example is an example that contains only 1 element that is smaller than previous, but it is not a almost-increasing sequence

So the most straight-forward logic (in pseudo-code) is something like:

```
def is_almost_increasing(seq):
for i in 1 to len(seq):
if seq[i] <= seq[i-1]:
return ( is_strictly_increasing(seq[:i-1] + seq[i:]
or is_strictly_increasing(seq[:i] + seq[i+1:] )
return true
(is_strictly_increasing is simple, will just leave it to you)
```

There are some tricks to make this even faster (e.g. you don’t really need to re-check the part that you have already confirmed increasing), but this should be a good starting point for you.

The simplest thing, I think for me, was to check pairs and remove the element that disturbs the sequence. after checking the adjecent element to i, I also check the surrounding elements to i. if by removing i I still have a disturbed sequence, then I remove i+1 instead, and take a step back to start checking again. Ive tested this on 38 different test cases. Let me know if there are any mistakes.

```
def almostIncreasingSequence(sequence):
count = 0
i =0
size = len(sequence)
if(sequence[0]>sequence[1]): #separate case for the first element
sequence.pop(0)
count+=1 #update the count everytime I remove an element
size-=1 # I change the size everytime i remove an element
while(i<size-1):
if sequence[i]>=sequence[i+1]:
count+=1
if(sequence[i+1]<=sequence[i-1]):
sequence.pop(i+1)
else:
sequence.pop(i)
size = len(sequence)
if i>0:
i-=1
else:
i+=1
if count>1:
return False
else:
return True
```

Well the way i figured out was using another array of ignore index which matched the false condition so that the loop would not be using those indexes and if the condition matches more than one time than it is not an almost increasing sequece.

Here I used ignoreindex list and added those index which matched the condition. The loop would ignore the index number using the list so that it would not end up checking same number twice. I tried to do it simply by removing the element from the list itself but somehow `def almostIncreasingSequence(sequence):

```
count = 0
ignoreindex = []
for i in range(0,len(sequence)-1):
for j in range(i+1,len(sequence)):
if i not in ignoreindex:
if j not in ignoreindex:
print("The index are %d,%d"%(i,j))
if sequence[j] <= sequence[i]:
print(i,j)
count += 1
print(count)
# if the same number are at two different location ignore the later index
if sequence[j] == sequence[i] and j - i > 1:
ignoreindex.append(j)
# else ignore the earlier index
else:
ignoreindex.append(i)
print(sequence)
print(ignoreindex)
if count > 1:
return False
return True`
```

Wow, this has been a hard challenge.

I think I have written a solution that will be understandable to a newbie also.

```
def solution(sequence):
if len(sequence) < 3: # since list with only 1 element is strictly increasing and
# with 2 elements we can always remove 1 to make it strictly increasing
return True
original_sequence = sequence.copy()
# original_sequence = sequence
# there is one problem with copying lists in this way. If you modify
#new_list, old_list is also modified. It is because the new list is
#referencing or pointing to the same old_list object.
position_to_pop = 0 #this will be used to remember the position where the strictly increasing does not hold
# for example 11,31,21,11 will give position_to_pop as index 2(21) in the for loop below...if it doesn't work then we remove the index 1 (31) to check whether it makes the list strictly increasing
if is_sequence_increasing(sequence):
return True
else:
for index, num in enumerate(sequence):
if index != len(sequence) -1: # if statment since we want to loop until second last item
if sequence[index+1] <= num:
position_to_pop = index + 1
break #breaking since we do not want to check further in the for loop
sequence.pop(position_to_pop) #first removing right integer(index+1) where the problem occured
if is_sequence_increasing(sequence):
return True
else: # if the first remove of the right integer doesn't work then we need to remove the left integer and see whether it fixes the issue
original_sequence.pop(position_to_pop-1)
if is_sequence_increasing(original_sequence):
return True
return False
def is_sequence_increasing(sequence_to_check):
for index, num in enumerate(sequence_to_check):
if index != len(sequence_to_check) -1:
if sequence_to_check[index+1] <= num:
return False
return True
```