web-dev-qa-db-fra.com

Trouver le plus petit entier positif qui ne se produise pas dans une séquence donnée

J'essayais de résoudre un problème dans Codility fourni ci-dessous, 

Ecrire une fonction:

class Solution { public int solution(int[] A); }

que, étant donné un tableau A de N entiers, retourne le plus petit entier positif (supérieur à 0) qui ne se produit pas dans A.

Par exemple, étant donné que A = [1, 3, 6, 4, 1, 2], la fonction doit renvoyer 5.

Given A = [1, 2, 3], the function should return 4.

Given A = [−1, −3], the function should return 1.

Suppose que:

N est un entier compris dans l'intervalle [1..100.000]; Chaque élément du tableau A est un entier compris dans l'intervalle [−1 000 000.,1 000 000] . Complexité:

la complexité temporelle attendue dans le pire cas est O (N); la complexité attendue dans l'espace pire des cas est O(N) (sans compter la mémoire requise pour les arguments d'entrée).

J'écris la solution ci-dessous qui donne une faible performance, cependant, je ne vois pas le bogue. 

public static int solution(int[] A) {

        Set<Integer> set = new TreeSet<>();

        for (int a : A) {
            set.add(a);
        }

        int N = set.size();

        int[] C = new int[N];

        int index = 0;

        for (int a : set) {
            C[index++] = a;
        }

        for (int i = 0; i < N; i++) {

            if (C[i] > 0 && C[i] <= N) {
                C[i] = 0;
            }
        }

        for (int i = 0; i < N; i++) {

            if (C[i] != 0) {
                return (i + 1);
            }
        }

        return (N + 1);
    }

Le score est fourni ici, 

 enter image description here

Je vais continuer à enquêter moi-même, mais s'il vous plaît informez-moi si vous pouvez voir mieux. 

Je vous remercie. 

3
Arefe

Si la durée d'exécution attendue doit être linéaire, vous ne pouvez pas utiliser une TreeSet, qui trie l'entrée et requiert donc O(NlogN). Par conséquent, vous devez utiliser un HashSet, qui nécessite O(N) temps pour ajouter des éléments N.

De plus, vous n'avez pas besoin de 4 boucles. Il suffit d'ajouter tous les éléments d'entrée positifs à une HashSet (première boucle), puis de trouver le premier entier positif non inclus dans cet ensemble (deuxième boucle).

int N = A.length;
Set<Integer> set = new HashSet<>();
for (int a : A) {
    if (a > 0) {
        set.add(a);
    }
}
for (int i = 1; i <= N + 1; i++) {
    if (!set.contains(i)) {
        return i;
    }
}
7
Eran

Tu en fais trop. Vous avez créé un TreeSet qui est un ensemble d'ordre de nombres entiers, puis vous avez essayé de le transformer en tableau. Parcourez plutôt la liste et ignorez toutes les valeurs négatives. Une fois que vous avez trouvé des valeurs positives, commencez à compter l'index. Si l'index est supérieur au nombre, l'ensemble a sauté une valeur positive.

int index = 1;
for(int a: set){
    if(a>0){
        if(a>index){
            return index;
        } else{
            index++;
        }
    }
}
return index;

Mise à jour pour les valeurs négatives.

Une solution différente qui est O(n) serait d'utiliser un tableau. C'est comme la solution de hachage.

int N = A.length;
int[] hashed = new int[N];

for( int i: A){
    if(i>0 && i<=N){
        hashed[i-1] = 1;
    }
}

for(int i = 0; i<N; i++){
    if(hash[i]==0){
        return i+1;
    }
}
return N+1;

Cela pourrait être optimisé davantage en comptant la limite supérieure pour la deuxième boucle.

2
matt

Pas besoin de stocker quoi que ce soit. Pas besoin de hashsets. (Mémoire supplémentaire), vous pouvez le faire lorsque vous vous déplacez dans le tableau. Cependant, le tableau doit être trié. Et nous savons que la valeur minimale est de 1

import Java.util.Arrays;
class Solution {
    public int solution(int[] A) {
        Arrays.sort(A);     
        int min = 1; 
            int cap = A.length; //for efficiency — no need to calculate or access the array object’s length property per iteration 

        for (int i = 0; i < cap; i++){
            if(A[i] == min){
                min++;
            }
        }   
        //min = ( min <= 0 ) ? 1:min; //this means: if (min <= 0 ){min =1}else{min = min} you can also do: if min <1 for better efficiency/less jumps
        return min;    
    }
}
1
TimeTrax

Je trouve une autre solution pour le faire avec un stockage supplémentaire, 

/*
* if A = [-1,2] the solution works fine
* */
public static int solution(int[] A) {

    int N = A.length;

    int[] C = new int[N];

    /*
     * Mark A[i] as visited by making A[A[i] - 1] negative
     * */
    for (int i = 0; i < N; i++) {

        /*
         * we need the absolute value for the duplicates
         * */
        int j = Math.abs(A[i]) - 1;

        if (j >= 0 && j < N && A[j] > 0) {
            C[j] = -A[j];
        }
    }

    for (int i = 0; i < N; i++) {

        if (C[i] == 0) {
            return i + 1;
        }
    }

    return N + 1;
}
1
Arefe
//My recursive solution:

class Solution {
    public int solution(int[] A) {
        return next(1, A);
    }
    public int next(int b, int[] A) {
        for (int a : A){
            if (b==a)
                return next(++b, A);
        }
        return b;
    }
}
1
Renato Caffer
    public int solution(int[] A) {

    int res = 0;
    HashSet<Integer> list = new HashSet<>();

    for (int i : A) list.add(i);
    for (int i = 1; i < 1000000; i++) {
        if(!list.contains(i)){
            res = i;
            break;
        }
    }
    return res;
}
1
Nik Kogan

Si la complexité de l'espace est O(1) et que le tableau peut être modifié, il pourrait être le suivant:

public int getFirstSmallestPositiveNumber(int[] arr) {
    // set positions of non-positive or out of range elements as free (use 0 as marker)
    for (int i = 0; i < arr.length; i++) {
        if (arr[i] <= 0 || arr[i] > arr.length) {
            arr[i] = 0;
        }
    }

    //iterate through the whole array again mapping elements [1,n] to positions [0, n-1]
    for (int i = 0; i < arr.length; i++) {
        int prev = arr[i];
        // while elements are not on their correct positions keep putting them there
        while (prev > 0 && arr[prev - 1] != prev) {
            int next = arr[prev - 1];
            arr[prev - 1] = prev;
            prev = next;
        }
    }

    // now, the first unmapped position is the smallest element
    for (int i = 0; i < arr.length; i++) {
        if (arr[i] != i + 1) {
            return i + 1;
        }
    }
    return arr.length + 1;
}

@Test
public void testGetFirstSmallestPositiveNumber() {
    int[][] arrays = new int[][]{{1,-1,-5,-3,3,4,2,8},
      {5, 4, 3, 2, 1}, 
      {0, 3, -2, -1, 1}};

    for (int i = 0; i < arrays.length; i++) {
        System.out.println(getFirstSmallestPositiveNumber(arrays[i]));
    }
}  

Sortie:

5

6

2

1
Anatolii
package Consumer;


import Java.util.Arrays;
import Java.util.List;
import Java.util.stream.Collectors;

public class codility {
public static void main(String a[])
    {
        int[] A = {1,9,8,7,6,4,2,3};
        int B[]= {-7,-5,-9};
        int C[] ={1,-2,3};
        int D[] ={1,2,3};
        int E[] = {-1};
        int F[] = {0};
        int G[] = {-1000000};
        System.out.println(getSmall(F));
    }
    public static int getSmall(int[] A)
    {
        int j=0;
        if(A.length < 1 || A.length > 100000) return -1;
        List<Integer> intList = Arrays.stream(A).boxed().sorted().collect(Collectors.toList());
         if(intList.get(0) < -1000000 || intList.get(intList.size()-1) > 1000000) return -1;
         if(intList.get(intList.size()-1) < 0) return 1;
        int count=0;         
         for(int i=1; i<=intList.size();i++)
         {
             if(!intList.contains(i))return i;
             count++;
         }
         if(count==intList.size()) return ++count;
        return -1;
    } 
}
1
Swanand Kanekar

Le moyen le plus simple utilisant la boucle while: 

fun solution(A: IntArray): Int {
    var value = 1
    var find = false
    while(value < A.size) {
        val iterator = A.iterator()
        while (iterator.hasNext()) {
            if (value == iterator.nextInt()) {
                find = true
                value++
            }
        }
        if (!find) {
            break
        } else {
            find = false
        }
    }
    return value
}
0
lomak

Rejoindre la conversation en retard. Basé sur:

https://codereview.stackexchange.com/a/179091/184415

Il existe en effet une solution de complexité O(n) à ce problème même si des entrées en double sont impliquées dans la saisie:

solution(A)
Filter out non-positive values from A
For each int in filtered
    Let a zero-based index be the absolute value of the int - 1
    If the filtered range can be accessed by that index  and  filtered[index] is not negative
        Make the value in filtered[index] negative

For each index in filtered
    if filtered[index] is positive
        return the index + 1 (to one-based)

If none of the elements in filtered is positive
    return the length of filtered + 1 (to one-based)

So an array A = [1, 2, 3, 5, 6], would have the following transformations:

abs(A[0]) = 1, to_0idx = 0, A[0] = 1, make_negative(A[0]), A = [-1,  2,  3,  5,  6]
abs(A[1]) = 2, to_0idx = 1, A[1] = 2, make_negative(A[1]), A = [-1, -2,  3,  5,  6]
abs(A[2]) = 3, to_0idx = 2, A[2] = 3, make_negative(A[2]), A = [-1, -2, -3,  5,  6]
abs(A[3]) = 5, to_0idx = 4, A[4] = 6, make_negative(A[4]), A = [-1, -2, -3,  5, -6]
abs(A[4]) = 6, to_0idx = 5, A[5] is inaccessible,          A = [-1, -2, -3,  5, -6]

A linear search for the first positive value returns an index of 3. Converting back to a one-based index results in solution(A)=3+1=4

Voici une implémentation de l'algorithme suggéré en C # (cela devrait être simple de le convertir en jargon Java - coupe-moi un peu de mou):

public int solution(int[] A)
{
    var positivesOnlySet = A
        .Where(x => x > 0)
        .ToArray();

    if (!positivesOnlySet.Any())
        return 1;

    var totalCount = positivesOnlySet.Length;
    for (var i = 0; i < totalCount; i++) //O(n) complexity
    {
        var abs = Math.Abs(positivesOnlySet[i]) - 1;
        if (abs < totalCount && positivesOnlySet[abs] > 0) //notice the greater than zero check 
            positivesOnlySet[abs] = -positivesOnlySet[abs];
    }

    for (var i = 0; i < totalCount; i++) //O(n) complexity
    {
        if (positivesOnlySet[i] > 0)
            return i + 1;
    }

    return totalCount + 1;
}
0
XDS

Cela pourrait vous aider, cela devrait bien fonctionner!

public static int sol(int[] A)
{
    boolean flag =false;
    for(int i=1; i<=1000000;i++ ) {
        for(int j=0;j<A.length;j++) {
            if(A[j]==i) {
                flag = false;
                break;
            }else {
                flag = true;
            }
        }
        if(flag) {
            return i;
        }
    }
    return 1;
}
0
saichander

Implémentation Python de la solution. Obtenir l'ensemble du tableau - Cela garantit que nous n'avons que des éléments uniques. Continuez ensuite à vérifier jusqu'à ce que la valeur ne soit plus présente dans le jeu. Imprimez la valeur suivante en sortie et renvoyez-la. 

def solution(A):
# write your code in Python 3.6
    a = set(A)
    i = 1
    while True:
        if i in A:
            i+=1
        else:
            return i
    return i
    pass
0
Ankit Shah

Je pense que l’utilisation de structures telles que: sets ou dict pour stocker des valeurs uniques n’est pas la meilleure solution, car vous finissez par rechercher un élément dans une boucle qui mène à la complexité O (N * N) ou en utilisant une autre boucle pour vérifier le manque valeur qui vous laisse avec une complexité linéaire O(N), mais vous passez plus de temps qu'une seule boucle.

En ce qui concerne l'espace de stockage, l'utilisation d'une structure de tableau de compteurs n'est pas optimale car vous allouez des blocs de mémoire MaxValue même lorsque votre tableau ne contient qu'un seul élément.

Donc, je pense que la meilleure solution utilise une seule boucle, évitant les structures et implémentant des conditions pour arrêter les itérations quand elle n’est plus nécessaire:

public int solution(int[] A) {
    // write your code in Java SE 8
    int len = A.length;
    int min=1;

    Arrays.sort(A);

    if(A[len-1]>0)
    for(int i=0; i<len; i++){
        if(A[i]>0){
            if(A[i]==min) min=min+1;
            if(A[i]>min) break;
        }
    }
    return min;
}

De cette façon, vous obtiendrez une complexité de O(N) ou O (N * log (N)), donc dans le meilleur des cas vous êtes sous la complexité O(N)

0
Dankks

Essayez ce code ça marche pour moi 

import Java.util.*;
    class Solution {
        public static int solution(int[] A) {
            // write your code in Java SE 8
            int m = Arrays.stream(A).max().getAsInt(); //Storing maximum value 
            if (m < 1) // In case all values in our array are negative 
            { 
                return 1; 
            } 
            if (A.length == 1) { 

                //If it contains only one element 
                if (A[0] == 1) { 
                    return 2; 
                } else { 
                    return 1; 
                } 
            } 
            int min = A[0];
            int max= A[0];
            int sm = 1;

            HashSet<Integer> set = new HashSet<Integer>();

            for(int i=0;i<A.length;i++){
                set.add(A[i]);

                if(A[i]<min){
                    min = A[i];
                }
                if(A[i]>max){
                    max = A[i];
                }
            }

            if(min <= 0){
                min = 1;
            }

            if(max <= 0){
                max = 1;
            }

            boolean fnd = false;
            for(int i=min;i<=max;i++){
                if(i>0 && !set.contains(i)){
                    sm = i;
                    fnd = true;
                    break;
                }
                else continue;

            }
            if(fnd)
                return sm; 
            else return max +1;
        }

              public static void main(String args[]){

               Scanner s=new Scanner(System.in);

            System.out.println("enter number of elements");

            int n=s.nextInt();

            int arr[]=new int[n];

            System.out.println("enter elements");

            for(int i=0;i<n;i++){//for reading array
                arr[i]=s.nextInt();

            }

        int array[] = arr;

        // Calling getMax() method for getting max value
        int max = solution(array);
        System.out.println("Maximum Value is: "+max);

      }
    }
0
Umesh Sonawane