Dan Öz
Dan Öz

Reputation: 351

Obtain a strictly increasing sequence python

Question:

"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.

Note: sequence a0, a1, ..., an is considered to be a strictly increasing if a0 < a1 < ... < an. Sequence containing only one element is also considered to be strictly increasing.

Examples:

Here's my code:

def solution(sequence):
    if len(sequence) == 1:
        return True
    else:
        count = 0
        for i in range(0,len(sequence) - 1):
            if sequence[i] >= sequence[i + 1]:
                count = count + 1
        for i in range(0,len(sequence) - 2):
            if sequence[i] >= sequence[i + 2]:
                count = count + 1
    return count <= 1

My code covers three cases:

Case 1: when the sequence is just one element long. I caught that in the first if statement.

Case 2: If there's more than one down-step – a case where the neighbour is less than the element being considered – then there is no way to adjust the sequence with just one removal, and so we get false (count > 1). I caught this in the first if statement.

Case 3: There are some cases, however, where there is only one down-step but there is still no way to remove just one element. This happens when the second element along is also less than the element being considered. For example, with [1,4,3,2] even if you removed the 3, you would still get a downstep. Now I covered this case by doing a second check, which checked whether the element two along is less, and if it is, then we add to the count.

Case 4: There is a case my code doesn't cover, which seems to be the only one, and that is when an element's neighbour and the next element along are both smaller than the element under consideration, but we could solve the issue just by getting rid of the element under consideration. So, with [1,4,2,3] both 2 and 3 are smaller than 4, but if we just got rid of the 4, then we're good. This case can occur either when the problem element is the first in the sequence or not. I'm not sure how to capture this properly. I suppose you might add in a conditional which looked at whether i-2 is less than i+1, but this won't work when i indexes the first element and it's quite cumbersome. I'm not sure how to go sort this out.

I'm quite sure I've overcomplicated things and what really is needed is to step back and think of a less piece-meal solution, but I'm stuck. Could anyone help? Note that we don't have to actually obtain the strictly increasing sequence; we just have to see whether we could.

Upvotes: 1

Views: 2729

Answers (6)

Alvaro Corona
Alvaro Corona

Reputation: 1

def solution(sequence):
boolean_list = []
setted = set(sequence)
#this if checks for 2 or more duplicated numbers
if (len(sequence) - len(setted)) >= 2:
    return False
else:
    #this for loop runs for every i item in sequence list
    for i in sequence:
        test = []
        #this for loop creates a test list without i item
        for j in sequence:               
            if j != i:
                test.append(j)
        # this variable checks if all the items in the test list are in ascending order
        is_ascending = all(test[x] <= test[x+1] for x in range(len(test)-1))
        # this is a list of boolean values with the result of every case
        boolean_list.append(is_ascending)
    # this returns True if at least one case is True else it returns False
    return any(boolean_list)

Upvotes: 0

manoj
manoj

Reputation: 11

Try this

def solution(sequence):
    n = len(sequence)
    for i in range(n):
        count = 0
        trail = sequence[:]
        del trail[i]
        m = len(trail)
        for j in range(m-1):
            if trail[j] >= trail[j+1]:
                count += 1
        if count == 0:
            return True
    return False

This is not efficient nor optimized but it does the work.

Upvotes: 1

gog
gog

Reputation: 11347

Let's split the input into at most two increasing subsequences. If this is not possible, return false.

If there's only one sequence, return true.

If the length of either sequence is 1, the answer is true - we simply remove this element.

Otherwise we can join two sequences by either removing the last item from the first sequence, or the first item of the second one. That is,

 if a[j-2] < a[j]     -> ok, remove a[j - 1]
 if a[j-1] < a[j + 1] -> ok, remove a[j]

where j is the index where the second sequence starts.

Code:

def check(a):
    j = 0

    for i in range(1, len(a)):
        if a[i - 1] >= a[i]:
            if j > 0:
                return None
            j = i

    if j == 0:
        return a

    if j == 1:
        return a[1:]

    if j == len(a) - 1:
        return a[:-1]

    if a[j - 2] < a[j]:
        return a[:(j - 1)] + a[j:]

    if a[j - 1] < a[j + 1]:
        return a[:j] + a[(j + 1):]

    return None


assert check([2, 4, 6, 8]) == [2, 4, 6, 8], 'j == 0'
assert check([9, 4, 6, 8]) == [4, 6, 8], 'j == 1'
assert check([4, 6, 8, 1]) == [4, 6, 8], 'j == len-1'
assert check([2, 4, 9, 6, 8]) == [2, 4, 6, 8], 'j-2 < j'
assert check([2, 4, 1, 6, 8]) == [2, 4, 6, 8], 'j-1 < j+1'

assert check([2, 2, 2, 2]) is None, 'early return'
assert check([2, 8, 9, 6, 1]) is None, 'early return'

assert check([2, 4, 9, 3, 5]) is None, 'last return'

assert check([2]) == [2]

Upvotes: 1

OrenIshShalom
OrenIshShalom

Reputation: 7152

Here is an idea you can a look at (edited after comments)

def distinct(L: list[int]) -> bool:
    return len(L) == len(set(L))

def almost_increasing(L: list[int]) -> bool:

    # some trivial cases
    if len(L) <= 2:                                   return True
    if L[1: ] == sorted(L[1: ]) and distinct(L[1: ]): return True
    if L[:-1] == sorted(L[:-1]) and distinct(L[:-1]): return True
    
    return any(
        L[  :i] == sorted(L[  :i]) and distinct(L[  :i]) and
        L[i+1:] == sorted(L[i+1:]) and distinct(L[i+1:]) and
        L[i-1 ] < L[i+1]
        for i in range(1, len(L)-1)
    )

And here is a nice way you can test it with hypothesis and pytest:

@given(L=st.lists(st.integers(), min_size=2, max_size=6))
def test_almost_increasing(L: list[int]):

    expected = False
    for i in range(len(L)):
        Lcopy = L.copy()
        del Lcopy[i]
        expected |= (Lcopy == sorted(Lcopy) and distinct(Lcopy))
    
    received = almost_increasing(L)
    assert received == expected

Upvotes: 1

will f
will f

Reputation: 483

def solution(sequence):
    """determine strict increase"""
    sequence_length = len(sequence)
    if (
        sequence_length == 0
        or not len(set(sequence)) + 1 >= sequence_length
    ):
        return False
    return True

Upvotes: -1

Inozem
Inozem

Reputation: 183

Try this:

def is_solution(list_to_check):
    if len(list_to_check) == 1:
        return True
    for i in range(1, len(list_to_check)):
        if list_to_check[i] <= list_to_check[i - 1]:
            new_list = list_to_check[:i - 1] + list_to_check[i:]
            if (list_to_check[i] > list_to_check[i - 2]
                and new_list == sorted(new_list)):
                return True
            elif (i == len(list_to_check) - 1
                  and list_to_check[:-1] == sorted(list_to_check[:-1])):
                return True
    return False


if __name__ == '__main__':
    list_to_check = [1, 2, 1]
    print(is_solution(list_to_check))

Upvotes: 0

Related Questions