存储100万个电话号码

时间:2011-03-10 16:13:59

标签: algorithm data-structures

存储100万个电话号码的最有效方式是什么?

显然这是Google的面试问题,请提出您的意见。

14 个答案:

答案 0 :(得分:44)

如果记忆是我们最大的考虑因素,那么我们根本不需要存储数字,只需存储i和i + 1之间的差值。

现在,如果数字范围为200 0000 - 999 9999,那么可能有7,999,999个电话号码。由于我们有100万个数字,如果我们假设它们是均匀分布的,我们在连续数n_i和n_i + 1之间的预期距离为E = n_i + 1 - n_i~8(3位)。因此,对于32位int,我们可能存储多达10个连续偏移(〜400kb最佳总内存占用量),但是我们可能会遇到需要大于8的偏移量的情况(也许我们有400个,或者1500?)。在这种情况下,我们可以简单地保留int的前2位作为标题,告诉我们用什么帧大小来读取它存储的位。例如,我们可能使用:00 = 3x10,01 = 5x6,10 = 7x4,11 = 1 * 30.

答案 1 :(得分:29)

以ASCII格式写出,以空格分隔。

使用您喜欢的压缩算法压缩生成的字符串。如果顺序不重要,首先对它们进行排序可能有助于压缩,让您在一起更加重复。

哦,你想要有效的随机访问吗?然后你应该说。

答案 2 :(得分:10)

可能的解决方案是

  1. 对数字进行排序
  2. 将增量从一个数字编码到下一个数字
  3. Delta频率分布将高度倾斜。

    我使用简单的类似BER的打包方法,使用7 + 3 + 3 + ...位编码进行增量;编码功能是

    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)
    

    (两个参数7和3是通过实验确定的)

    通过这种方法,我获得了一百万个10位数字,前五个数字从千个随机前缀中选择,平均每个数字为8.83位(打包大小为1104188)。

答案 3 :(得分:7)

数字块上的霍夫曼编码可能会产生非常好的结果。如果数字是混合类型(例如一些美国,一些在海外,包括访问代码),则需要另外几位来指定它们的类型(以及使用哪些块)。

如果数字在某个小范围内 - 例如。七位数 - 最紧凑的存储方式可能是将它们视为整数,对它们进行排序,并存储(霍夫曼编码的)值差异。例如。如果有7个数字的10 ^ 6个数字(10 ^ 7种可能性),你需要大约每个数字的log2(10)〜= 3.3比特。

答案 4 :(得分:7)

首先我发现它们从不以0开头,因为0在开始时用作转义字符。所以我可以简单地将电话号码视为整数。如果不是这种情况,我只需在数字前加一个“1”,然后将其转换为整数。这不会显着影响编码效率(可能是几个字节的恒定开销)。如果电话号码内的10位数字之外还有其他字符,则只需使用高于10的基数进行编码。但这会影响效率。

我按尺寸递增顺序排序。然后计算差异。然后使用protobuf序列化差异作为打包的重复字段。

这个方法类似于RexKerr的方法,除了我使用protobuf的懒惰解决方案而不是霍夫曼编码器。可能有点大,因为protobuf整数编码是通用的,并没有考虑电话号码的概率分布。但是编码要容易得多,因为我只需要使用现有的protobuf序列化器。一旦超过UInt64的大小,这将会出现问题,即电话号码超过19位。文件格式仍然支持它,但大多数实现都不支持。

没有索引访问时间会非常糟糕,但它应该相当紧凑。

答案 5 :(得分:7)

三元搜索树是一种特殊的trie数据结构,它将具有内存效率,并且仍然可以启用(如trie)部分匹配。

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

答案 6 :(得分:5)

如果您查看North American Numbering Plan的数据字段表示,您会得出结论:1 + NPA + NXX + xxxx的美国电话号码可以存储在少于22个每个区号中每个电话号码字段的位数。添加区号和代表任何美国(加拿大)电话号码的数据可以轻松地适合32位。这是一个位字段表示 - 而不是int。

然而,你对此的看法不应该是以美国为中心的。当然,问题不仅仅在于将一百万个电话号码压缩到最少的位数。

美国电话号码可以短至3位数(内部PBX拨号方案)长达22位数(1 + NPA + NXX + xxxx + 11位内部PBX拨号方案)。如果电话号码限制为ITU specified number format,则最多15位数加上1位“+”。

然后,您应该定义3位数和22位数(或ITU的15位数)之间的任何电话号码的可变位字段表示,每个位字段具有X位标题字段以指示字段的格式。

然后将这些位字段放入压缩的bit array中。可能的位数组可以用trie或其他方法索引。

这样做的效率取决于100万个电话号码的格式,您想要访问它们的速度,以及未来不同格式的数据结构对于更多电话号码的灵活性。它不只是计算“正确”答案恕我直言的位。

答案 7 :(得分:2)

假设我们假设每个电话号码与(3位数区号)的美国格式一致 - (7位数字)

这是一个10位数字。

但是,在处理电话号码时有订婚规则。它们是稀疏的,因为并非所有可能的区域代码都被使用。在这种情况下,一棵简单的树就可以了。我的意思是考虑一下......加拿大你只需要269 + 26。这是非常小的,你已经削减了大部分空间PLUS增加了搜索时间。不仅如此,还可以增加位置信息。

之后,你有一个7位数字。这可以存储在一个32位整数中。在插入时排序,你有一个非常快速的检索机制,因为你可以对数字的其余部分进行二进制搜索。

答案 8 :(得分:1)

我猜一个未签名的Int32或国际号码是一个无符号的Int64

使用32位无符号整数,即4MB

答案 9 :(得分:1)

这实际上取决于您希望在存储的数据库上运行哪些操作。

简单的方法是使用无符号整数,如果你只需要存储它们,那么使用字典对原始文本表示进行一些压缩可能会更小。

答案 10 :(得分:1)

在求职面试中,这个问题的重点是确定申请人解决问题的能力。因为问题的焦点是 记忆效率 ,在我看来,正确的答案是询问采访者:“电话号码是国际的,还是仅限于一个国家?”如果这些数字仅限于一个国家,那么每个国家/地区都有按州和城市分配电话号码的简单规则,从而简化了最大化内存效率的任务。

答案 11 :(得分:1)

我想我们可以在这里使用100万像素的Bit Vector。

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);
}

答案 12 :(得分:1)

800万位,每位1(使用)或0(可用),用于800万个数字之一 示例

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

答案 13 :(得分:-11)

/******************************************************************************** 

  Filename: Phone_Numbers.c
    Author: Paul Romsky
   Company: Autoliv AEL
      Date: 11 MAR 2013

   Problem: What is the most efficient way, memory-wise, to store 1 million 
            phone numbers?

   Caveats: There is no mention if the numbers are contiguous or not, so, to save 
            space the numbers should be contiguous.  The problem (as a specification) 
            is rather vague and leaves a lot to interpretation, so many different 
            methods may be desired, but which one(s) desired is not surely known.

            Are the phone numbers just the extension (last four digits), or do they
            include the exchange (the leading 3 digits), or do they also include 
            area code and/or international numbers?

            There is no mention of the first number, only the range of numbers, so 
            the first number 000-0000 is used.  Although many numbers are not 
            normally used, they could in fact be used as valid number sequences 
            within the phone companies and are thus phone numbers nonetheless.

  Solution: A simple algorithm. If the numbers are not contiguous a fractal algorithm
            could be used.

            A standard ANSI C compiler should pack this program into a very small
            assembly module of only a few bytes.

 Revisions:

 Rev Date        By                   Description
 --- ----------- -------------------- -------------------------------------------
  -  11 MAR 2013 P. Romsky            Initial Coding

 ********************************************************************************/

/* Includes */

#include <stdio.h>


/* Functions */

/******************************************************************************** 
 *
 * Main Entry Point
 *
 ********************************************************************************/
int main()
{
  unsigned int Number;

  /* 1,000,000 Phone Number Storage 000-0000 through 999-9999 */

  for(Number = 0000000; Number < 10000000; Number++)
  {
    /* Retrieve Numbers */

    printf("%07u\n", Number);
  }

  return 0;
}

/* End */