13 votes

Solve almostIncreasingSequence (Combats de code)

Étant donné une séquence d'entiers sous forme de tableau, déterminez s'il est possible d'obtenir une séquence strictement croissante en n'enlevant pas plus d'un élément du tableau.

Exemple

Pour la séquence [1, 3, 2, 1] , le résultat devrait être :

almostIncreasingSequence(sequence) = false;

Aucun élément de ce tableau ne peut être supprimé pour obtenir une séquence strictement croissante.

Pour la séquence [1, 3, 2] , le résultat devrait être :

almostIncreasingSequence(sequence) = true.

Vous pouvez retirer 3 du tableau pour obtenir la séquence strictement croissante [1, 2]. Vous pouvez également retirer 2 pour obtenir la séquence strictement croissante [1, 3].

Mon code :

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

Mais il ne peut pas passer tous les tests.

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

22voto

Rory Daulton Points 11787

Votre algorithme est beaucoup trop simpliste. Vous avez une bonne idée, en vérifiant des paires consécutives d'éléments que l'élément précédent est inférieur à l'élément suivant, mais il faut aller plus loin.

Instaurer une routine first_bad_pair(sequence) qui vérifie que toutes les paires d'éléments sont dans l'ordre. Si c'est le cas, il renvoie la valeur -1 . Sinon, il renvoie l'indice de l'élément précédent : il s'agit d'une valeur de 0 a n-2 . L'algorithme qui fonctionnerait alors consisterait à vérifier la liste originale. Si elle fonctionne, c'est parfait, mais si ce n'est pas le cas, il faut essayer de supprimer les éléments incriminés antérieurs ou postérieurs. Si l'un ou l'autre fonctionne, c'est bon, sinon ce n'est pas bon.

Je peux penser à d'autres algorithmes, mais celui-ci semble le plus simple. Si vous n'aimez pas les listes temporaires jusqu'à deux qui sont faites en combinant deux tranches de la liste originale, l'équivalent pourrait être fait avec des comparaisons dans la liste originale en utilisant plus de if déclarations.

Voici un code Python qui passe tous les tests que vous avez indiqués.

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

Si vous souhaitez éviter ces listes temporaires, voici un autre code qui présente une routine de vérification des paires plus compliquée.

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

Et voici les tests que j'ai utilisés.

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

5voto

sukai Points 51

Voici le mien. J'espère que cela vous sera utile :

def almostIncreasingSequence(sequence):

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

    #Set up a new function to see if it's 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

4voto

Ashish Singh Points 51

La raison pour laquelle votre modeste algorithme échoue ici (à part le "=" manquant dans le retour) est qu'il compte simplement les éléments qui sont plus grands que le suivant et renvoie un résultat si ce nombre est supérieur à 1.

L'important est de regarder la liste après en avoir retiré un élément à la fois, et de confirmer qu'il s'agit toujours d'un trié liste.

Ma tentative est très courte et fonctionne pour tous les scénarios. Elle échoue à la contrainte de temps sur le dernier ensemble de tests cachés de l'exercice.

enter image description here

Comme le nom du problème le suggère, je voulais directement comparer la liste à sa version triée, et traiter le cas "presque" plus tard - d'où la séquence almostIncreasingSequence. i.e.. :

if sequence==sorted(sequence):
   .
   .

Mais comme le dit le problème :

déterminer s'il est possible d'obtenir une suite strictement croissante en ne supprimant pas plus d'un élément du tableau (à la fois).

J'ai commencé à visualiser la liste en supprimant un élément à la fois pendant l'itération, et en vérifiant si le reste de la liste est une version triée d'elle-même. C'est ainsi que j'en suis arrivé à ceci :

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

C'est là que j'ai pu constater que si cette condition est vraie pour la liste complète, alors nous avons ce qu'il faut - une séquence presque incrémentale ! J'ai donc complété mon code de cette manière :

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)

Cette solution échoue toujours sur des listes telles que [1, 1, 1, 2, 3]. Comme @rory-daulton l'a noté dans ses commentaires, nous devons faire la différence entre un "sorted" et un "increasingSequence" dans ce problème. Alors que le test [1, 1, 1, 2, 3] est trié, il est sur une séquence croissante comme demandé dans le problème. Pour résoudre ce problème, voici le code final avec une condition d'une ligne ajoutée pour vérifier la présence de nombres identiques consécutifs :

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

Comme cela ne respecte toujours pas la limite de temps d'exécution pour le dernier test (la liste doit être très grande), je cherche encore un moyen d'optimiser cette solution.

1voto

TImmuh Points 32

Je travaille toujours sur le mien. Je l'ai écrit comme ça mais je n'arrive pas à passer les 3 derniers tests cachés.

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

1voto

mTv Points 378

C'était un exercice très intéressant.

J'ai procédé de la manière suivante :

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X