Решить почти повышение уровня (Codefights)

Учитывая последовательность целых чисел в виде массива, определите, можно ли получить строго возрастающую последовательность, удалив из массива не более одного элемента.

Пример

Для последовательности [1, 3, 2, 1] вывод должен быть:

almostIncreasingSequence(sequence) = false;

В этом массиве нет ни одного элемента, который можно удалить, чтобы получить строго возрастающую последовательность.

Для последовательности [1, 3, 2] выход должен быть:

almostIncreasingSequence(sequence) = true.

Вы можете удалить 3 из массива, чтобы получить строго возрастающую последовательность [1, 2]. В качестве альтернативы вы можете удалить 2, чтобы получить строго возрастающую последовательность [1, 3].

Мой код:

def almostIncreasingSequence(sequence):
    c= 0
    for i in range(len(sequence)-1):
        if sequence[i]>=sequence[i+1]:
            c +=1
    return c<1

Но он не может пройти все тесты.

input: [1, 3, 2]
Output:false
Expected Output:true

Input: [10, 1, 2, 3, 4, 5]
Output: false
Expected Output: true

Input: [0, -2, 5, 6]
Output: false
Expected Output: true

input:  [1, 1]
Output: false
Expected Output: true

Input: [1, 2, 3, 4, 3, 6]
Output: false
Expected Output: true

Input: [1, 2, 3, 4, 99, 5, 6]
Output: false
Expected Output: true

Ответ 1

Ваш алгоритм слишком упрощен. У вас есть правильная идея, проверяющая последовательные пары элементов, что более ранний элемент меньше, чем более поздний элемент, но требуется больше.

Выполните процедуру first_bad_pair(sequence), которая проверит список, в котором находятся все пары элементов. Если да, верните значение -1. В противном случае верните индекс предыдущего элемента: это будет значение от 0 до n-2. Тогда один алгоритм, который будет работать, - проверить исходный список. Если он работает, отлично, но если не попытаться удалить предыдущие или более поздние элементы-нарушители. Если кто-то из них работает, отлично, в противном случае не очень хорошо.

Я могу думать о других алгоритмах, но это кажется самым простым. Если вам не нравятся временные списки "вверх-вниз", которые создаются путем объединения двух срезов исходного списка, эквивалент может быть выполнен с помощью сравнения в исходном списке с использованием более выражений if.

Вот код Python, который передает все тесты, которые вы показываете.

def first_bad_pair(sequence):
    """Return the first index of a pair of elements where the earlier
    element is not less than the later elements. If no such pair
    exists, return -1."""
    for i in range(len(sequence)-1):
        if sequence[i] >= sequence[i+1]:
            return i
    return -1

def almostIncreasingSequence(sequence):
    """Return whether it is possible to obtain a strictly increasing
    sequence by removing no more than one element from the array."""
    j = first_bad_pair(sequence)
    if j == -1:
        return True  # List is increasing
    if first_bad_pair(sequence[j-1:j] + sequence[j+1:]) == -1:
        return True  # Deleting earlier element makes increasing
    if first_bad_pair(sequence[j:j+1] + sequence[j+2:]) == -1:
        return True  # Deleting later element makes increasing
    return False  # Deleting either does not make increasing

Если вы хотите избежать этих временных списков, вот еще один код, который имеет более сложную процедуру проверки пары.

def first_bad_pair(sequence, k):
    """Return the first index of a pair of elements in sequence[]
    for indices k-1, k+1, k+2, k+3, ... where the earlier element is
    not less than the later element. If no such pair exists, return -1."""
    if 0 < k < len(sequence) - 1:
        if sequence[k-1] >= sequence[k+1]:
            return k-1
    for i in range(k+1, len(sequence)-1):
        if sequence[i] >= sequence[i+1]:
            return i
    return -1

def almostIncreasingSequence(sequence):
    """Return whether it is possible to obtain a strictly increasing
    sequence by removing no more than one element from the array."""
    j = first_bad_pair(sequence, -1)
    if j == -1:
        return True  # List is increasing
    if first_bad_pair(sequence, j) == -1:
        return True  # Deleting earlier element makes increasing
    if first_bad_pair(sequence, j+1) == -1:
        return True  # Deleting later element makes increasing
    return False  # Deleting either does not make increasing

И вот те тесты, которые я использовал.

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]))

Ответ 2

Это мое. Надеемся, что вы сочтете это полезным:

def almostIncreasingSequence(sequence):

    #Take out the edge cases
    if len(sequence) <= 2:
        return True

    #Set up a new function to see if it increasing sequence
    def IncreasingSequence(test_sequence):
        if len(test_sequence) == 2:
            if test_sequence[0] < test_sequence[1]:
                return True
        else:
            for i in range(0, len(test_sequence)-1):
                if test_sequence[i] >= test_sequence[i+1]:
                    return False
                else:
                    pass
            return True

    for i in range (0, len(sequence) - 1):
        if sequence[i] >= sequence [i+1]:
            #Either remove the current one or the next one
            test_seq1 = sequence[:i] + sequence[i+1:]
            test_seq2 = sequence[:i+1] + sequence[i+2:]
            if IncreasingSequence(test_seq1) == True:
                return True
            elif IncreasingSequence(test_seq2) == True:
                return True
            else:
                return False

Ответ 3

Причина, по которой ваш скромный алгоритм не работает здесь (кроме отсутствующего '=' взамен), заключается в том, что он просто считает элементы, которые больше, чем следующий, и возвращает результат, если это число больше 1.

В этом случае важно посмотреть на список после удаления из него по одному элементу за раз и убедиться, что это все еще отсортированный список.

Моя попытка этого очень коротка и работает для всех сценариев. Он не соответствует временному ограничению последнего скрытого теста, заданного в упражнении в одиночку.

enter image description here

Как следует из названия проблемы, я непосредственно хотел сравнить список с его отсортированной версией и позже обработать "почти" случай - таким образом, имея почти IncreasingSequence. т.е.:

if sequence==sorted(sequence):
   .
   .

Но, как говорит проблема:

определить, можно ли получить строго возрастающую последовательность, удаляя не более одного элемента из массива (за раз).

Я начал визуализировать список, удаляя элемент за раз во время итерации и проверяя, является ли остальная часть списка отсортированной версией. Таким образом, подводит меня к этому:

for i in range(len(sequence)):
    temp=sequence.copy()
    del temp[i]
    if temp==sorted(temp):
        .
        .

Именно здесь я смог увидеть, что если это условие верно для полного списка, то у нас есть то, что требуется - почти IncreasingSequence! Итак, я завершил свой код следующим образом:

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)

Это решение все еще не работает в таких списках, как [1, 1, 1, 2, 3]. Как отметил @rory-daulton в своих комментариях, мы должны различать "отсортированную" и "возрастающую последовательность" в этой задаче. В то время как тест [1, 1, 1, 2, 3] отсортирован, он имеет возрастающую последовательность, как того требует проблема. Для этого ниже приведен окончательный код с добавлением условия в одну строку для проверки последовательных одинаковых номеров:

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

Так как это все еще не соответствует времени выполнения последнего теста (список должен быть очень большим), я все еще ищу, есть ли способ оптимизировать это мое решение.

Ответ 4

Я все еще работаю над собой. Написал это так, но я не могу пройти последние 3 скрытых теста.

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

Ответ 5

Это было довольно крутое упражнение.

Я сделал это вот так:

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]))

Ответ 6

С Python3 я начал с чего-то вроде этого...

def almostIncreasingSequence(sequence):
    for i, x in enumerate(sequence):
        ret = False
        s = sequence[:i]+sequence[i+1:]
        for j, y in enumerate(s[1:]):
            if s[j+1] <= s[j]:
                ret = True
                break
            if ret:
                break
        if not ret:
            return True
    return False

Но продолжался тайм-аут на чеке # 29.

Я пнул себя, когда понял, что это тоже работает, но все же время от времени на # 29. Я не знаю, как ускорить его.

def almostIncreasingSequence(sequence):
    for i, x in enumerate(sequence):    
        s = sequence[:i]
        s.extend(sequence[i+1:])
        if s == sorted(set(s)):
            return True
    return False

Ответ 7

Вот мое простое решение

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

Ответ 8

Ну, вот и мое решение, Я думаю, что это немного чище, чем другие решения, предложенные здесь, поэтому я просто приведу его ниже.

Он в основном проверяет индекс, в котором значение i -th больше значения (i + 1) -th, если он находит такой индекс, проверяет, превращает ли какой-либо из этих двух список в увеличивающийся последовательность.

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

Ответ 9

boolean almostIncreasingSequence(int[] sequence) {
    int length = sequence.length;
    if(length ==1) return true;
    if(length ==2 && sequence[1] > sequence[0]) return true;
    int count = 0;
    int index = 0;
    boolean iter = true;

    while(iter){
        index = checkSequence(sequence,index);
        if(index != -1){
            count++;
            index++;
            if(index >= length-1){
                iter=false;
            }else if(index-1 !=0){
                if(sequence[index-1] <= sequence[index]){
                    iter=false;
                    count++;
                }else if(((sequence[index] <= sequence[index-2])) && ((sequence[index+1] <= sequence[index-1]))){
                    iter=false;
                    count++;                    
                }
            }
        }else{
            iter = false;
        }
    }
    if(count > 1) return false;
    return true;
}

 int checkSequence(int[] sequence, int index){
    for(; index < sequence.length-1; index++){
        if(sequence[index+1] <= sequence[index]){
            return index; 
        }
    }
    return -1;
}

Ответ 10

Ниже приведен код Python3, который я использовал, и он работал нормально:

def almostIncreasingSequence(sequence):
flag = False

if(len(sequence) < 3):
    return True

if(sequence == sorted(sequence)):
    if(len(sequence)==len(set(sequence))):
        return True

bigFlag = True
for i in range(len(sequence)):
    if(bigFlag and i < len(sequence)-1 and sequence[i] < sequence[i+1]):
        bigFlag = True
        continue
    tempSeq = sequence[:i] + sequence[i+1:]
    if(tempSeq == sorted(tempSeq)):
        if(len(tempSeq)==len(set(tempSeq))):
            flag = True
            break
    bigFlag = False
return flag

Ответ 11

Это работает в большинстве случаев, за исключением проблем с производительностью.

def almostIncreasingSequence(sequence):
    if len(sequence)==2:
        return sequence==sorted(list(sequence))
    else:
        for i in range(0,len(sequence)):
            newsequence=sequence[:i]+sequence[i+1:]
            if (newsequence==sorted(list(newsequence))) and len(newsequence)==len(set(newsequence)):
                return True
                break
            else:
                result=False
    return result

Ответ 12

Это мое решение,

def nearIncreasingSequence (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