Comptage des Nombres Premiers avec le Crible d'Euler

Énoncé du Problème

Étant donné un entier n, retournez le nombre de nombres premiers strictement inférieurs à n.

Exemples

Entrée : n = 10
Sortie : 4
Explication : Les nombres premiers inférieurs à 10 sont 2, 3, 5, 7.

Entrée : n = 0
Sortie : 0

Entrée : n = 1
Sortie : 0

Introduction aux Méthodes de Crible

Pour compter efficacement les nombres premiers, plusieurs algorithmes de crible existent. Parmi eux, le crible naïf, le crible d'Eratosthène et le crible d'Euler (aussi appelé crible linéaire) sont couramment utilisés. Le crible d'Euler offre la meilleure complexité temporelle, atteignant O(n), contrairement aux autres méthodes qui sont moins optimales pour de grandes valeurs de n.

Crible Naïf

Cette approche vérifie pour chaque nombre i entre 2 et n s'il possède des diviseurs dans l'intervale [2, √i]. Si aucun diviseur n'est trouvé, i est considéré comme premier. La complexité temporelle est de O(n√n).


bool est_premier(int valeur) {
    for (int diviseur = 2; diviseur * diviseur <= valeur; diviseur++) {
        if (valeur % diviseur == 0) return false;
    }
    return true;
}

Crible d'Eratosthène

Cette méthode élimine progressivement les multiplse des nombres premiers identifiés, à partir de 2. Elle possède une complexité de O(n log log n).


const int TAILLE_MAX = 1000010;
bool est_composite[TAILLE_MAX];
vector<int> liste_premiers;

void initialiser_crible(int borne) {
    for (int idx = 0; idx <= borne; idx++) est_composite[idx] = false;
    est_composite[0] = est_composite[1] = true;
    for (int candidat = 2; candidat <= borne; candidat++) {
        if (!est_composite[candidat]) {
            liste_premiers.push_back(candidat);
            for (int multiple = candidat * candidat; multiple <= borne; multiple += candidat) {
                est_composite[multiple] = true;
            }
        }
    }
}
</int>

Crible d'Euler (Crible Linéaire)

Le crible d'Euler garantit que chaque nombre composé est éliminé par son plus petit facteur premier, assuarnt ainsi une complexité linéaire O(n). Il évite les calculs redondants présents dans le crible d'Eratosthène.


bool marquage_non_premier[5000001];
vector<int> nombres_premiers;

void appliquer_crible_euler(int limite) {
    for (int nombre = 2; nombre <= limite; nombre++) {
        if (!marquage_non_premier[nombre]) {
            nombres_premiers.push_back(nombre);
        }
        for (int premier : nombres_premiers) {
            if (premier * nombre > limite) break;
            marquage_non_premier[premier * nombre] = true;
            if (nombre % premier == 0) break;
        }
    }
}

int compter_premiers(int n) {
    int total = 0;
    appliquer_crible_euler(n);
    for (int i = 2; i < n; i++) {
        if (!marquage_non_premier[i]) total++;
    }
    return total;
}
</int>

Étiquettes: C++ Crible d'Euler Crible d'Eratosthène Algorithmes de Crible Nombres Premiers

Publié le 4 juin à 01h44