web-dev-qa-db-fra.com

Complexité temporelle pour générer toutes les paires dans un tableau

Étant donné un tableau de nombres, générez toutes les paires uniques.

Par exemple, étant donné [ 1, 2, 3, 4, 5 ] la paire de numéros unique serait:

(1, 2), (1, 3), (1, 4), (1, 5)

(2, 3), (2, 4), (2, 5)

(3, 4), (3, 5)

(4, 5)

Ma solution est la suivante:

int[] numbers = new int[] { 1, 2, 3, 4, 5 };
HashSet<Pair> pairs = new HashSet<Pair>();

for(int i = 0; i < numbers.Length; i++)
{
    for(int j = i + 1, j < numbers.Length; j++)
    {
        pairs.Add(new Pair(numbers[i], numbers[j]));
    }
}

Je pense que la complexité temporelle pour cela ressemble à O (n2 - 1) soustraire 1 car l'itération de j est toujours 1 plus courte que i

Après avoir fait un peu de recherche sur ce type de problème, je ne trouve pas de réponses définitives pour savoir si cela peut être fait plus rapidement. Y a-t-il de meilleures solutions que O (n2 - 1)?

21
series0ne

Une des façons de penser à "existe-t-il un moyen plus rapide de résoudre le problème" consiste à examiner la taille de la sortie pour un format spécifique (que vous considérez comme "probablement le plus grand/le plus difficile à résoudre").

Si la sortie est O(n^2), vous ne pouvez pas résoudre le problème plus rapidement que dans O(n^2), car vous devez dépenser au moins O(1) pour chaque sortie.

Vous pouvez voir le modèle ici, si vous avez 5 nombres au format [1, 2, 3, 4, 5], Des paires uniques prennent

4 pairs in first row
3 pairs in second row
2 pairs...
1 pair

parce qu'ils ressemblent

(1, 2), (1, 3), (1, 4), (1, 5)

(2, 3), (2, 4), (2, 5)

(3, 4), (3, 5)

(4, 5)

Si vous avez 20 variables dans le tableau (au format [1, 2, 3,... 18, 19, 20]), Ce sera comme suit:

19 pairs
18 pairs
...
2 pairs
1 pair

Par conséquent, la taille de sortie est (n-1) + (n-2) + (n-3) ... + 3 + 2 + 1. Vous devez le additionner (regardez comment additionner la série) et le résultat est O(n^2)

Qu'est-ce qui a été prouvé?

Que le pire des cas est AT LEAST O(n^2).

Notez également qu'en ce moment, nous ne connaissons pas la véritable complexité du pire des cas - l'alghorithme peut être encore plus lent (nous constatons simplement que certaines entrées prennent O(n^2)). Nous savons avec certitude qu'au moins ces données prennent O(n^2). Il peut être plus rapide ou plus lent pour différentes entrées.


Conlusion: Nous avons la preuve que l'algorithme prend au moins O(n^2) temps (comme dans le pire des cas), vous avez créé un algorithme qui fonctionne au maximum de O(n^2) time (comme décrit dans spyc post) = Vous avez un algorithme optimal.


Informations supplémentaires sur la solution OP: Détecter les collisions avec HashSet n'est que "pseudoConstant" et uniquement pour les petits nombres et "un peu de chance". Il faut O(n) pour une grande quantité de nombres. Vous pouvez donc vous retrouver dans la sortie de n^2 Et chacun d'eux prend jusqu'à n pour être traité, ce qui conduit à la complexité de n^3.

Vous pouvez le résoudre en prétraitant la tâche:

1) Triez-le - cela ne prend que n log n, Cela n'affecte donc pas n^2

2) Supprimez les nombres qui se répètent plus de deux fois [1, 3, 3, 3, 5] -> [1, 3, 3, 5], C'est O(n)

3) Utilisez ensuite votre algorithme avec cette mise à jour:

3.1) Au début du cycle for i: if (number[i] == number[i-1]) continue;

3.2) Au début du cycle for j: N'oubliez pas la dernière paire. Lorsque vous ajoutez une nouvelle paire, recherchez la dernière paire et vérifiez si elle est identique ou non. Si oui - continue;

Exemple:

Input: [1, 3, 3, 5]

1)i=0, j=1, number[0]=1, number[1]=3 -> add (1, 3)
2)i=0, j=2, number[0]=1, number[2]=3 -> same as last pair, use continue
3)i=0, j=3, number[0]=1, number[3]=5 -> add (1, 5)
4)i=1, j=2, number[1]=3, number[2]=3 -> add (3, 3)
5)i=1, j=3, number[1]=3, number[3]=5 -> add (3, 5)
6)i=2, before go to j-cycle, check number[i] === number[i-1] It is true, use continue
41
libik

Il se déroule comme suit:

first for loop - O(n)
    second for loop - O(n-1)

Optimal Complexité temporelle:

enter image description here

  • Même si cette itération est négligeable, et vous devez calculer la complexité temporelle pour le pire des cas, qui est enter image description here

Vous pouvez également utiliser le coefficient binomial pour les permutations, pour obtenir le nombre de permutations d'une certaine chaîne. Par exemple:

enter image description here

Si vous avez 6 chiffres {0,1,2,3,4,5} (n = 6), et vous voulez savoir combien de permutations différentes vous pouvez faire, c'est-à-dire: (3 , 5), (5,3) etc ... puis le (k = 2, deux chiffres dans chaque groupe), la quantité de permutations sera:

enter image description here différentes permutations, notez cependant que dans ce cas (3,5), (5,3) sont comptés individuellement, donc l'ordre de tout est important. Si vous voulez que (5,3) et (3,5) soient comptés comme une seule combinaison alors l'équation se présente comme suit:

enter image description here


Exemple d'implémentation, calcul des permutations!

static long factorial(long x) // calcs the factorial TimeCmplx = O(n)
{
    if (x == 1)
        return x;
    return x * factorial(x - 1);
}

static long permutations(long n , long k) //Check that (n , k) >= 0
{            
    // Permutations , n!/(n-k)!
    return factorial(n) / factorial(n - k);
}
12
Yuval

Je pense que la complexité temporelle pour cela ressemble à O (n2 - 1) soustrayant 1 parce que l'itération de j est toujours 1 plus courte que i

Si cela importait (la notation big-O habituellement vous n'écrivez que le terme avec la croissance la plus rapide), là vous avez des itérations de i sur [0, n) contenant chacune une itération de j sur [i + 1, n) donc le nombre d'itérations est (n ∙ (n-1))/2 pas n²-1.

De plus, votre modification en HashSet plutôt qu'en liste modifie l'exécution dans le pire des cas, mais pas la valeur amortie - si Pair.GetHashCode () devait toujours renvoyer la même valeur, vous l'auriez augmentée jusqu'à O (n³), comme dans les cas où les collisions sont courantes, l'insertion de l'ensemble de hachage devient O(n) plutôt que constante.

5
Pete Kirkham

Il s'agit d'un algorithme aire d'un triangle.

Vous avez N entrées, et vous voulez n triangle de sorties.

Votre triangle de sortie a un hauteur de N-1 et un largeur de N-1.

Area of a triangle = height * width / 2
                   = (N-1)  * (N-1) / 2
                   = (N^2 - 2N + 1) / 2

O(n^2 - n) sera toujours le coût minimum/optimal de l'algorithme!

0
Oreo