web-dev-qa-db-fra.com

À partir d'un tableau d'entiers, trouvez le premier entier positif manquant en temps linéaire et en espace constant

En d'autres termes, recherchez le nombre entier positif le plus bas qui n'existe pas dans le tableau. Le tableau peut également contenir des doublons et des nombres négatifs. Cette question a été posée par Stripe lors de son entretien de programmation. J'ai conçu une solution pour les mêmes que ci-dessous:

#include<bits/stdc++.h>
using namespace std;

int main(){
    int arr[]={1,-1,-5,-3,3,4,2,8};
    int size= sizeof(arr)/sizeof(arr[0]);
    sort(arr, arr+size);
    int min=1;

    for(int i=0; i<size; i++){
        if(arr[i]>min) break;
        if(arr[i]==min) min=min+1;
    }
    cout<<min;
    return 0;
}

Ici, je commence par trier le tableau, puis par le parcourir une fois. Avant de parcourir le tableau, j’avais initialisé la variable "min" à 1. Maintenant, lorsque nous parcourons le tableau, lorsque nous obtenons un entier égal à min, nous incrémentons simplement la valeur de min. Cela garantit que la variable min contient le dernier entier le moins positif qui ne soit pas encore apparu. Pouvez-vous penser à une meilleure approche? Merci d'avance.

3
Jhanak Didwania

En supposant que le tableau peut être modifié,

  1. Nous divisons le tableau en 2 parties de sorte que la première partie se compose uniquement de nombres positifs. Supposons que nous ayons l’index de départ sous la forme 0 et l’index de fin sous la forme end (exclusif).

  2. Nous parcourons le tableau d'index 0 à end. Nous prenons la valeur absolue de l'élément à cet index - disons que la valeur est x

    1. Si x > end nous ne faisons rien. 
    2. Sinon, le signe de l'élément à l'index x-1 est négatif.
  3. Enfin, nous parcourons une nouvelle fois le tableau d'index 0 à end. Si nous rencontrons un élément positif à un index, nous générons index + 1. C'est la réponse Cependant, si nous ne rencontrons aucun élément positif, cela signifie que les entiers 1 à end apparaissent dans le tableau. Nous produisons end + 1

Il se peut également que tous les nombres soient non positifs, ce qui rend end = 0. La sortie end + 1 = 1 reste correcte.

Toutes les étapes peuvent être effectuées dans le temps O(n) et en utilisant l'espace O(1).

Exemple:

Initial Array:            1 -1 -5 -3 3 4 2 8
Step 1 partition:         1 8 2 4 3 | -3 -5 -1, end = 5

À l'étape 2, nous modifions les signes des nombres positifs pour déterminer quels entiers se sont déjà produits. Par exemple, ici array[2] = -2 < 0, cela suggère que 2 + 1 = 3 a déjà eu lieu dans le tableau. Fondamentalement, nous changeons la valeur de l'élément d'index i en négatif si i+1 est dans le tableau.

Step 2 Array changes to: -1 -8 -2 -4 3 | -3 -5 -1

À l'étape 3, si une valeur array[index] est positive, cela signifie que nous n'avons trouvé aucun entier de valeur index + 1 à l'étape 2.

Step 3: Traversing from index 0 to end, we find array[4] = 3 > 0
        The answer is 4 + 1 = 5
3
pmcarpan

L'algorithme de PMCarpan fonctionne.

Je pense que votre approche fonctionne, mais vous devez spécifier le type de tri que vous effectuez afin qu'il soit clair qu'il s'agit d'un tri linéaire et pas nécessairement d'une sorte complète du tableau entier. Cela se traduit par O(N) temps sans utiliser d'espace. 

Analysez le tableau, lorsque vous analysez si la valeur de votre index actuel est inférieure à la longueur du tableau, puis échangez-le avec la valeur actuellement dans cet index. Vous devez continuer l’échange jusqu’à ce que cela devienne plus logique d’échanger à chaque index. Ensuite, effectuez une autre analyse jusqu'à ce que vous trouviez un index incorrect.

Voici du code de travail en Python, bien que Python ne soit pas l'endroit pour faire ce genre de chose, lol.

def sortOfSort(arr) :
    for index in range(len(arr)) :
        checkValue = arr[index]

        while(checkValue > 0 and checkValue != index and checkValue < len(arr) and arr[checkValue] != checkValue) :
            arr[index] = arr[checkValue]
            arr[checkValue] = checkValue
            checkValue = arr[index]

    return arr[1:] + [arr[0]]

def findFirstMissingNumber(arr) :
    for x in range(len(arr)) :
        if (x+1 != arr[x]) :
            return x+1
    return len(arr) + 1

la partie retour arr [1:] provient du fait que, selon votre description, nous n'incluons pas zéro comme point de départ.

0
FredMan

En supposant que cette liste est modifiable sur place.
Idée: Utilisez les valeurs de la liste (dans la plage) pour auto-étiqueter les index de la liste. Renvoie le plus petit index non étiqueté de cette liste "étiquetée".
Par exemple: si la liste est composée de 4 nombres, la valeur "2" entraînera le marquage de l'index 1 ...
J'utilise des nombres complexes pour le "marquage" car il conserve la valeur dans la partie réelle. C'est-à-dire que l'ajout d'un 1j à une valeur le "repère" alors que la valeur elle-même est toujours récupérable dans la partie réelle ...

Voir l'implémentation Python3:

def foo(int_list):
    # "Tag" list values in-place
    # O(n)
    for i in int_list:
        # Remove imaginary "tag"
        if i.imag > 0:
            i = int(i.real)
        # Check positive i ints that are less than len(int_list)
        if 0 < i < len(int_list):
            # Add imaginary "tag"
            int_list[i-1] = (1j + int_list[i-1])

    # Iterate over the int_list
    # O(n)
    ctr = 0
    while ctr < len(int_list):
        # Return the first "un-tagged" index (+1)
        if int_list[ctr].imag == 0:
            return ctr + 1
        ctr += 1
    else:
        return len(int_list)


assert foo([3, 4, -1, 1]) == 2
assert foo([3, 4, 4, 4, 4, -1, 1]) == 2
assert foo([1, 2, 0]) == 3
assert foo([8, 1, 7]) == 2
0
pX0r