web-dev-qa-db-fra.com

Stocker 1 million de numéros de téléphone

Quelle est la manière la plus efficace, en termes de mémoire, de stocker 1 million de numéros de téléphone?

Apparemment, c'est une question d'entrevue chez Google, veuillez donner vos idées.

71
algo-geeks

Si la mémoire est notre plus grande considération, alors nous n'avons pas du tout besoin de stocker le nombre, juste le delta entre i et i + 1.

Maintenant, si les numéros vont de 200 0000 à 999 9999, il y a 7 999 999 numéros de téléphone possibles. Puisque nous avons 1 million de nombres, et si nous supposons qu'ils sont uniformément distribués, nous avons une distance attendue de E = n_i + 1 - n_i ~ 8 (3 bits) entre les nombres séquentiels n_i et n_i + 1. Donc, pour un int 32 bits, nous pourrions potentiellement stocker jusqu'à 10 décalages séquentiels (~ 400 Ko d'empreinte mémoire totale optimale), mais il est probable que nous aurons des cas où nous avons besoin d'un décalage supérieur à 8 (Peut-être que nous en avons 400 ou 1500 ??). Dans ce cas, nous pouvons simplement réserver les 2 premiers bits de l'int comme un en-tête qui nous indique quelle taille de trame nous utilisons pour lire les bits qu'il stocke. Par exemple, nous utilisons peut-être: 00 = 3x10, 01 = 5x6, 10 = 7x4, 11 = 1 * 30.

44
Rob Leclerc

Écrivez-les en ASCII, séparés par des espaces.

Compressez la chaîne résultante en utilisant votre algorithme de compression préféré. Si l'ordre n'est pas important, le tri en premier pourrait aider à la compression, vous donner plus de répétition plus rapprochés.

Oh, vouliez-vous un accès aléatoire efficace? Alors tu aurais dû dire.

29
Steve Jessop

Une solution possible est

  1. trier les nombres
  2. encoder les deltas d'un numéro au suivant

La distribution des fréquences delta sera fortement asymétrique.

J'ai fait une expérience en utilisant une approche de compression simple de type BER pour les deltas en utilisant un codage à 7 + 3 + 3 + ... bits; la fonction de codage était

def delta_write(x, b1, b2):
    lim = 1 << (b1 - 1)
    if x < lim:
        bit_write(x, b1)
    else:
        bit_write(lim + (x & (lim - 1)), b1)
        delta_write(x >> (b1 - 1), b2, b2)

(les deux paramètres 7 et 3 ont été déterminés expérimentalement)

Avec cette approche, j'ai obtenu un million de numéros à 10 chiffres avec les 5 premiers chiffres choisis parmi mille préfixes aléatoires avec une moyenne de 8,83 bits par numéro (taille compacte 1104188).

10
6502

Le codage de Huffman sur des blocs de chiffres donnerait probablement de très bons résultats. Si les numéros étaient de type mixte (par exemple, certains États-Unis, certains à l'étranger, y compris le code d'accès), vous auriez besoin d'un autre couple de bits pour spécifier de quel type il s'agissait (et donc quels blocs utiliser).

Si les chiffres étaient dans une petite plage - par exemple. sept chiffres - la façon la plus compacte de les stocker serait probablement de les traiter comme des nombres entiers, de les trier et de stocker les différences de valeurs (codées par Huffman). Par exemple. avec 10 ^ 6 nombres en 7 chiffres (10 ^ 7 possibilités), vous vous attendez à avoir besoin d'environ log2 (10) ~ = 3,3 bits par nombre.

7
Rex Kerr

Un arbre de recherche ternaire qui est une structure de données trie spéciale sera efficace en mémoire et permettra toujours (comme trie) une correspondance partielle.

http://en.wikipedia.org/wiki/Ternary_search_tree

7
Cem

D'abord, j'observe qu'ils ne commencent jamais par 0 car 0 est utilisé comme caractère d'échappement au début. Je peux donc simplement considérer les numéros de téléphone comme des nombres entiers. Si ce n'était pas le cas, je préfère simplement ajouter un "1" au nombre, puis le convertir en entier. Cela n'affecterait pas significativement l'efficacité du codage (surcharge probablement constante de quelques octets). S'il y a d'autres caractères en dehors des 10 chiffres à l'intérieur des numéros de téléphone, il suffit d'encoder avec une base supérieure à 10. Cela nuira cependant à l'efficacité.

Je les commanderais par taille croissante. Calculez ensuite les différences. Et sérialisez ensuite les différences à l'aide de protobuf en tant que champs répétés compressés.

Cette méthode est similaire à la méthode de RexKerr, sauf que j'utilise la solution paresseuse de protobuf sur un encodeur huffman. Probablement un peu plus grand car le codage entier protobuf est à usage général et ne prend pas en compte la distribution de probabilité des numéros de téléphone. Mais c'est beaucoup plus facile à coder car j'ai juste besoin d'utiliser un sérialiseur protobuf existant. Cela deviendra problématique une fois que vous dépasserez la taille d'un UInt64, c'est-à-dire qu'il y a des numéros de téléphone de plus de 19 chiffres. Le format de fichier le prend toujours en charge, mais pas la plupart des implémentations.

Sans index, les temps d'accès seront assez mauvais, mais ils devraient être plutôt compacts.

7
CodesInChaos

Si vous regardez les représentations des champs de données du plan de numérotation nord-américain , vous conclurez que les numéros de téléphone américains de 1 + [~ # ~] npa [~ # ~] + [~ # ~] nxx [~ # ~] + xxxx peuvent être stockés dans moins de 22 bits par champ de numéro de téléphone dans chaque indicatif régional. Ajoutez les indicatifs régionaux et les données représentant n'importe quel numéro de téléphone américain (plus canadien) peuvent tenir confortablement en 32 bits. C'est comme une représentation de champ de bits - pas comme un int.

Cependant, votre réflexion à ce sujet ne devrait pas être centrée sur les États-Unis. La question n'est certainement pas qu'un exercice consiste à compresser 1 million de numéros de téléphone en un minimum de bits.

Les numéros de téléphone aux États-Unis peuvent être aussi courts que 3 chiffres (plans de numérotation internes PBX) jusqu'à 22 chiffres (1 + NPA + NXX + xxxx + 11 chiffres internes PBX plan de numérotation). Si le numéro de téléphone était limité au format numérique spécifié par l'UIT , vous avez jusqu'à 15 chiffres plus 1 bit pour le '+'.

Vous devriez alors probablement définir une représentation de champ de bits variable de tout numéro de téléphone entre 3 chiffres et 22 chiffres (ou 15 chiffres pour ITU) avec chaque champ de bits ayant un champ d'en-tête X bits pour indiquer le format du champ.

Ensuite, placez ces champs de bits dans un tableau de bits compressé . Potentiellement, ce tableau de bits peut être indexé avec un trie ou une autre méthode.

L'efficacité est basée sur le format du million de numéros de téléphone, la rapidité avec laquelle vous souhaitez y accéder et la flexibilité de cette structure de données pour plus de numéros de téléphone à l'avenir dans différents formats. Il ne s'agit pas seulement de compter les bits pour la "bonne" réponse à mon humble avis.

5
the wolf

Supposons que nous supposions que chaque numéro de téléphone est conforme au format américain de (indicatif régional à 3 chiffres) - (numéro à 7 chiffres)

Il s'agit d'un nombre à 10 chiffres.

Cependant, il existe des règles d'engagement lorsqu'il s'agit de numéros de téléphone. Ils sont rares, d'une part, ce qui signifie que tous les indicatifs régionaux possibles ne sont pas utilisés. Dans ce cas, un simple arbre est ok. Je veux dire, pensez-y ... vous n'avez besoin que de 269 + 26 pour le Canada. C'est assez petit et vous avez réduit une grande partie de l'espace PLUS le temps de recherche. Non seulement cela, mais il peut être augmenté pour les informations de localisation.

Après cela, vous avez un numéro à 7 chiffres. Cela peut être stocké dans un seul entier 32 bits. Triez sur l'insertion, et vous disposez d'un mécanisme de récupération assez rapide, car vous pouvez effectuer une recherche binaire sur le reste du nombre.

2
Collin Cusce

8 millions de bits avec chaque bit 1(used) ou 0(available) pour un exemple de 8 millions de nombres)

100 0000
900 0000
= 8 million phone numbers, bit 1 = 1000000 and bit 8 million = 9000000 
1
BK2

Lors d'un entretien d'embauche, le point de cette question est de mesurer les compétences du candidat en résolution de problèmes. Parce que l'objectif de la question est l'efficacité de la mémoire , à mon avis, la bonne réponse est de demander à l'intervieweur: " numéros de téléphone internationaux ou sont-ils limités à un seul pays? " Si les numéros sont limités à un seul pays, la tâche de maximiser l'efficacité de la mémoire est simplifiée par le fait que chaque pays a des règles simples pour la distribution des numéros de téléphone par état et par ville.

1
user223264

Je pense que nous pouvons utiliser ici Bit Vector de taille 1 million.

Exemple Java:

private BitSet dir = new BitSet(1000000);

public void addTelephoneNumber(int number)
{
    dir.set(number);
}


public void removeTelephoneNumber(int number)
{
    if (dir.get(number))
    {
        dir.flip(number);
    }
}


public boolean isNumberPresent(int number)
{
    return dir.get(number);
}
1
Shailesh Kushwaha

Je suppose qu'un Int32 non signé ou pour les numéros internationaux un Int64 non signé

Utiliser des entiers non signés 32 bits qui seraient 4 Mo

1
cusimar9

Cela dépend vraiment des opérations que vous souhaitez exécuter sur la base de données stockée.

L'approche triviale utilise des entiers non signés, si vous avez juste besoin de les stocker, une compression sur la représentation du texte brut à l'aide d'un dictionnaire serait probablement plus petite.

1
Kornel Kisielewicz