Algorithm 存储千个电话号码的最有效方法

Algorithm 存储千个电话号码的最有效方法,algorithm,data-structures,Algorithm,Data Structures,这是一个谷歌面试问题: 大约有1000个电话号码需要存储,每个号码有10位数字。您可以假设每个数字的前5位在1000个数字中是相同的。您必须执行以下操作: A.搜索是否存在给定的数字。 B打印所有号码 最有效的节省空间的方法是什么 我回答了哈希表的问题,后来又给哈夫曼编码,但我的面试官说我的方向不对。请帮帮我 使用后缀trie有帮助吗 理想情况下,1000个数字的存储需要每个数字4个字节,所以总共需要4000个字节来存储1000个数字。定量地说,我希望把存储量减少到4000字节,这是我的采访者向

这是一个谷歌面试问题:

大约有1000个电话号码需要存储,每个号码有10位数字。您可以假设每个数字的前5位在1000个数字中是相同的。您必须执行以下操作: A.搜索是否存在给定的数字。 B打印所有号码

最有效的节省空间的方法是什么

我回答了哈希表的问题,后来又给哈夫曼编码,但我的面试官说我的方向不对。请帮帮我

使用后缀trie有帮助吗


理想情况下,1000个数字的存储需要每个数字4个字节,所以总共需要4000个字节来存储1000个数字。定量地说,我希望把存储量减少到4000字节,这是我的采访者向我解释的。

< P>我可能会考虑使用压缩版的A(可能是米莎的建议)。 这将自动利用它们都有一个共同的前缀这一事实

搜索将在固定时间内执行,打印将在线性时间内执行。


我曾经接受过一次采访,他们询问了数据结构。我忘记了“Array”。

在下面的内容中,我将数字视为整数变量(与字符串相反):

  • 对数字进行排序
  • 将每个数字分成前五位和后五位
  • 数字的前五位是相同的,所以只存储一次。这将需要17位存储
  • 分别存储每个数字的最后五位数字。这将需要每个数字17位
  • 总而言之:前17位是公共前缀,随后的1000组17位是按升序存储的每个数字的最后五位

    1000个号码总共需要2128字节,或者每10位电话号码需要17.017位


    搜索是
    O(logn)
    (二进制搜索),完整枚举是
    O(n)

    这是Bentley编程珍珠中众所周知的问题

    解决方案: 从数字中去掉前五位数字,因为每个数字的前五位数字相同 号码。然后使用位运算来表示剩余的9999个可能值 价值您只需要2^17位来表示数字。一点一滴 表示一个数字。如果设置了位,则电话号码在电话簿中

    要打印所有数字,只需打印设置位的所有数字 与前缀连在一起。要搜索给定的数字,请执行必要的位 检查数字的位表示的算术

    您可以在O(1)中搜索一个数字,并且由于位表示,空间效率是最大的


    HTH Chris.

    将此视为一个纯粹的理论问题,并将实现过程视为辅助,唯一最有效的方法是在一个巨大的索引表中索引所有可能的10000个最后数字集。假设您有1000个精确的数字,您将需要略多于8000位来唯一标识当前集合。不可能有更大的压缩,因为这样会有两个状态相同的集合

    这样做的问题是,您必须将程序中的2^8000个集合中的每一个表示为lut,而即使是google也无法远程实现这一点

    查找将是O(1),打印所有数字O(n)。插入是O(2^8000),理论上是O(1),但实际上是不可用的

    在一次采访中,如果我确信该公司正在寻找一位能够跳出思维定势的人,我只会给出这个答案。否则,这可能会让你看起来像一个理论家,与现实世界无关

    编辑:好的,这里有一个“实现”

    构建实现的步骤:

  • 取一个大小为100000*(1000选择100000)位的常量数组。是的,我知道这个阵列需要比宇宙中的原子多几个数量级的空间
  • 将这个大数组分成10万块
  • 在每个数据块中,为最后五个数字的一个特定组合存储一个位数组
  • 这不是程序,而是一种元程序,它将构造一个巨大的LUT,现在可以在程序中使用。在计算空间效率时,通常不计算程序中的常量,所以在进行最终计算时,我们不关心这个数组

    以下是如何使用此LUT:

  • 当有人给你1000个数字时,你将前五位数字分开存储
  • 找出数组中与此集合匹配的块
  • 将集合的编号存储在一个8074位的编号中(称为c)
  • 这意味着对于存储,我们只需要8091位,我们在这里证明了这是最佳编码。然而,找到正确的区块需要O(100000*(100000选择1000)),根据数学规则,这是O(1),但在实践中总是需要比宇宙时间更长的时间

    但查找很简单:

  • 前五位数字的条带(剩余数字称为n’)
  • 测试它们是否匹配
  • 计算i=c*100000+n'
  • 检查LUT中i处的位是否设置为1
  • 打印所有数字也很简单(实际上需要O(100000)=O(1),因为您总是要检查当前块的所有位,所以我在上面计算错了)

    我不会称之为“实现”,因为它公然无视这些限制(宇宙的大小和这个宇宙已经存在或这个地球将存在的时间)。然而,理论上这是最佳解决方案。对于较小的问题,这实际上是可以做到的,有时也会做到。例如,这是这种编码方式的一个例子,可以作为递归排序算法的最后一步,以获得较大的加速。

    这里是对该方法的改进。考虑在数据结构中使用三个“层”:第一个是常数
    i := 0;
    for K from 0 to ceil(99999 / 2^k) do
      while i < a[K] do
        print(c * 10^5 + K * 2^k + b[i]);
        i := i + 1;
      end do;
    end do;
    
    17 (prefix) + 1,782 (counts) + 7,000 (offsets) = 8,799 bits = 1100 bytes
    
    Size in bits = 17 (prefix) + 1,000 + 99,999/2^x + x * 1,000
    
    typedef struct _number {
    
        uint16_t number;
        bool overflow;
    }Number;
    
    overflow = (number5digits & 0x10000) >> 4;
    number = number5digits & 0x1111;
    
    //Something like this should work
    number5digits = number | (overflow << 4);
    
    for(int i=0;i<1000;i++) cout << const5digits << number5digits << endl;
    
    Variance | Encoded Value -----------+---------------- 0 | 0 -1 | 1 1 | 2 -2 | 3 2 | 4 -3 | 5 3 | 6 ... | ... -31 | 61 31 | 62 -32 | 63 -----------|--------------- 6 bits 32 | 64 -33 | 65 33 | 66 ... | ... -98 | 195 98 | 196 -99 | 197 -----------|--------------- End of ZigZag 100 | 198 101 | 199 ... | ... 3996 | 4094 3997 | 4095 -----------|--------------- 12 bits 3998 | 4096 3999 | 4097 ... | ... 262045 | 262143 -----------|--------------- 18 bits Variance | Encoded Bits -----------+---------------- 0 | 000000 0 5 | 001010 0 -8 | 001111 0 -32 | 111111 0 32 | 000000 1 000001 0 -99 | 000101 1 000011 0 177 | 010011 1 000100 0 14444 | 001110 1 100011 1 000011 0 BIN 000101001011001000100110010000011001 000110 1 010110 1 00001 0 PH# 55555-12345 55555-12448 55555-12491 POS 1 2 3 Amount of encoded numbers | 1-chunk | 2-chunks | 3-chunks | Total bits ---------+----------+----------+------------ 999 | 0 | 0 | 7025 800 | 180 | 19 | 8551 0 | 974 | 25 | 14193
    00001 = 00001
    12345 = 12345
    50001 = reserved
    00001 = 50001
    12345 = 62345
    65000 = end-of-list