IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Algorithmes et structures de données Discussion :

Trouver des paires et des triplets dans une liste


Sujet :

Algorithmes et structures de données

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut Trouver des paires et des triplets dans une liste
    Hello,

    On m'a récemment poser une question intéressante (pour une fois ) lors d'un entretien d'embauche :
    Comment trouver des paires dans une liste de nombres et quelle est la complexité ?
    Exemple : Dans la liste [1, 1, 1, 2, 4, 2, 2, 2]
    Résultats : 3 paires (1, 2, 2), il y a 3 '1' -> on peut faire qu'une seule paire avec et 4 '2' -> 2 paires de '2'

    Il y a une solution en O(n), on ajoute tous les nombres dans une hash map, et pour chaque nombre on divise le nombre d’occurrences par deux.
    code (C++)
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    std::unordered_map<int, int> hm;
    auto nbs = {1, 1, 1, 2, 4, 2, 2, 2};
    for(auto n: nbs) {
       ++hm[n];
    }
    int nbPairs = 0;
    for(auto const& kv: hm) {
       nbPairs += (kv.second / 2);
    }
    std::cout << nbPairs << std::endl;

    Puis, puis même question pour trouver des triplets.
    Exemple : Dans la liste [1, 1, 1, 2, 4, 2, 2, 2]
    Résultats : 2 triplets (1, 2), il y a 3 '1' -> 1 triplet; 4 '2' -> 1 triplet

    Sur le coup, j'ai donné un algo en O(n²), qui en y réfléchissant n'a pas de sens : appliquer 2 fois l'algo précédent de manière imbriqué. La complexité en O(n²) que j'ai donné n'a pas choqué, l'algo par contre ... :p
    Alors que le même algo en O(n) semble marcher :
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    std::unordered_map<int, int> hm;
    auto nbs = {1, 1, 1, 2, 4, 2, 2, 2};
    for(auto n: nbs) {
       ++hm[n];
    }
    int nbPairs = 0;
    for(auto const& kv: hm) {
       nbPairs += (kv.second / 3);
    }
    std::cout << nbPairs << std::endl;

    Du coup ma question : Si une complexité en O(n²) ne choque pas, c'est qu'il y a un algo (probablement naïf); Mais j'arrive pas à trouver, une idée ?

  2. #2
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    salut,

    un peu au pif, pour chaque valeur du tableau parcourir l'intégralité des valeurs restantes ?

  3. #3
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut
    Hum,

    Ça pose pas de problème avec les triplets détectés plusieurs fois ?
    Pour '2', il serait détecté 2 fois :
    - Itération sur le 1er '2' : [4, 2, 2, 2] -> 1 paire, + 1 triplet
    - Itération sur le 2eme '2' : [2, 2] -> 1 paire, + 1 triplet
    => 2 est compté comme 2 triplets.

    Quelque chose comme ça marcherait ?
    Code C++ : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    auto nbs = { 1, 1, 1, 2, 4, 2, 2, 2 };
    int nbPairs = 0;
    for (auto b = nbs.begin(), e = nbs.end(); b != e; ++b) {
    	int n = 0;
    	for (auto it = b + 1; it != e; ++it) {
    		if (*it == *b) {
    			++n;
    		}
    	}
    	nbPairs += n / 2;
    }
    nbPairs /= 3;
    ++nbPairs;
    std::cout << nbPairs << std::endl;

    Division du nombre de pairs par 3 + 1 à la fin pour corriger la détection multiple. C'est correct ?

  4. #4
    Expert confirmé Avatar de Flodelarab
    Homme Profil pro
    Inscrit en
    Septembre 2005
    Messages
    5 292
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente (Poitou Charente)

    Informations forums :
    Inscription : Septembre 2005
    Messages : 5 292
    Par défaut
    Bonjour

    J'ai rien compris.
    Tu comptes les occurrences pour chaque motif et tu divises par 2 pour les couples, par 3 pour les triplets et par 6 pour les hexuplets.
    Mais tu trouves ça trop simple. Alors tu viens ici demander plus compliqué ?

    Euh ... pourquoi faire compliqué ?

    Et puisqu'on se balance du code à la figure, tiens, prends

    Code bash : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    $ cat triplets.txt 
    1
    1
    1
    2
    4
    2
    2
    2 
    $ awk '{a[$1]++;} END{for (i in a) print i,"->",int(a[i]/2),"couple(s)";}' triplets.txt                                                                                                              
    4 -> 0 couple(s)
    1 -> 1 couple(s)
    2 -> 2 couple(s)
    $ awk '{a[$1]++;} END{for (i in a) print i,"->",int(a[i]/3),"triplet(s)";}' triplets.txt                                                                                                             
    4 -> 0 triplet(s)
    1 -> 1 triplet(s)
    2 -> 1 triplet(s)
    $ awk '{a[$1]++;} END{for (i in a) print i,"->",int(a[i]/6),"hexuplet(s)";}' triplets.txt 
    4 -> 0 hexuplet(s)
    1 -> 0 hexuplet(s)
    2 -> 0 hexuplet(s)

  5. #5
    Membre Expert
    Homme Profil pro
    Étudiant
    Inscrit en
    Juin 2012
    Messages
    1 711
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Juin 2012
    Messages : 1 711
    Par défaut
    Citation Envoyé par Flodelarab Voir le message
    Mais tu trouves ça trop simple. Alors tu viens ici demander plus compliqué ?

    Euh ... pourquoi faire compliqué ?
    Par simple curiosité, une solution existe en O(n²), je voyais pas trop comment.

  6. #6
    Expert confirmé Avatar de BufferBob
    Profil pro
    responsable R&D vidage de truites
    Inscrit en
    Novembre 2010
    Messages
    3 041
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations professionnelles :
    Activité : responsable R&D vidage de truites

    Informations forums :
    Inscription : Novembre 2010
    Messages : 3 041
    Par défaut
    Citation Envoyé par Iradrille Voir le message
    Ça pose pas de problème avec les triplets détectés plusieurs fois ?
    ben l'idée c'est de "retirer" (pop ?) les valeurs du tableau au fur et à mesure, nécessairement

    alors en C++ flemme mais en python (2.7) ça donnerait un truc comme ça très naïvement :
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # -*- coding: utf8 -*-
    L = [1, 1, 1, 2, 4, 2, 2, 2]
    paires = []
    while True:
       current = L[0]
       L.pop(0)  # reste le tableau moins le premier élément qui sert de référence (current)
       for i in range(len(L)): # on parcourt tout le tableau restant donc
          if L[i] == current:
             L.pop(i)  # on retire du tableau l'élément appairé via son indice
             paires.append(current) # et on ajoute l'élément dont on a trouvé la paire dans une autre liste, pour affichage à la fin...
             print '- paire de %d trouvée, reste %s' % (current, str(L))
             break
       if len(L) < 2: # s'il reste 0 ou 1 élément dans le tableau on ne peut plus trouver de paire, donc on sort
          break
    print '%d paires trouvées %s' % (len(paires), str(paires))

    et le résultat :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    - paire de 1 trouvée, reste [1, 2, 4, 2, 2, 2]
    - paire de 2 trouvée, reste [4, 2, 2]
    - paire de 2 trouvée, reste []
    3 paires trouvées [1, 2, 2]

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 9
    Dernier message: 26/03/2011, 09h46
  2. liste récursive des fichiers d'un dossier dans une liste
    Par identifiant_bidon dans le forum Langage
    Réponses: 2
    Dernier message: 30/06/2010, 16h33
  3. scanner des dossiers et les mettre dans une liste
    Par niklos0 dans le forum Programmation et administration système
    Réponses: 1
    Dernier message: 08/09/2008, 14h34
  4. Réponses: 4
    Dernier message: 11/07/2007, 19h28
  5. Réponses: 4
    Dernier message: 24/04/2003, 22h28

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo