所以,我正在观看其中一个关于他们如何进行采访的谷歌视频(https://www.youtube.com/watch?v=XKu_SEDAykw),我发现他们的解决方案很奇怪。由于有很多聪明的人在谷歌工作,我现在想知道我是否有问题,或者他们是否做错了。让我总结一下你不想看的任务和解决方案:
任务是为以下问题提供有效的算法:
给定一个整数数组A和一个单独的整数a,找到两个索引i,j,这样A [i] + A [j] = a。
他们从排序的数组开始,产生一个很好的线性时间算法。但随后采访者询问如果数组没有排序会发生什么。他们提出了以下线性时间算法(他们说首先对数组进行排序然后使用它们的线性时间算法太慢,尽管它会在nlogn时间内运行):
他们从头到尾遍历数组,并使用哈希集来存储他们已经看过的数字。然后他们只需要检查数组的每个索引的哈希集(即我已经看到了我需要得到总和的数字)并且因为显然可能在恒定时间内,整个算法在线性时间内运行(基本上是哈希集的数量* Array.length)。
现在我的批评:我认为这个解决方案存在一个巨大的缺陷,主要在于碰撞的可能性。由于他们假设nlogn很慢,我们可以假设哈希集少于logn许多不同的条目。现在,给定任何大的输入,当将n个数字散列到最多logn多个集合时,获得冲突的概率趋向于1。因此,他们交易速度非常适度(他们假设该数组的数量为100亿,但是日志(基数2)仍然小于30.但是,将此速度与散列集算法相匹配将意味着超过3亿对于几乎确定的错误算法,数字将被散列到相同的位置。
我要么用哈希误解了一些东西,要么就是这个问题的一个糟糕的解决方案。同样,安全nlogn算法并不比它们给出的算法慢得多,除非数组变得如此之大以至于哈希算法肯定会发生冲突。
如果一个为小数组抛出硬币的常数时间算法并且总是对大数组说“是”,那么我不会感到惊讶,它们的平均成功率与它们的哈希集解决方案相同。
如果我误解了哈希的问题,请指出这一点,因为我觉得很难相信他们会在一家顶尖的计算机工程公司犯这样的错误。
答案 0 :(得分:5)
要清楚,“哈希集”是一个哈希表,其中键是整个条目;没有相关的值,所以关于密钥的唯一有趣的事实是它存在。这是哈希表实现中的一个小细节。
正如已经指出的那样,你的陈述没有根据哈希集的大小需要小于log n以减少查找时间。反过来说:哈希集的大小(桶的数量)应该是数据集大小的线性,因此哈希链的预期长度是O(1)。 (对于复杂性分析,哈希链的预期长度是1还是1,000并不重要:两者都是O(1)。)
但是即使预期的哈希表查找不是O(1),对散列进行散列仍然有很大的优势:散列很容易并行化。这对谷歌来说非常重要,因为只有并行算法才能应对谷歌大小的数据集。
在实践中,这个问题的一个googly解决方案(我想:我没有看过视频)将使用两个不同的哈希值。第一个哈希将每个数字分配给服务器,因此它具有非常大的桶大小,因为每个服务器都有大量数据。然后,每个服务器使用自己的哈希函数将自己的数据映射到自己的桶中。
现在我可以并行扫描整个数据集(使用其他服务器),并且对于每个条目,请询问相应的存储服务器(我使用主哈希计算),附加逆是否在其数据集中。由于每个条目只能存储在一个服务器(或一组服务器上,如果为了可靠性而复制数据),我实际上不必打扰不相关的服务器。 (在实践中,我会采取一堆查询,然后通过服务器进行存储,然后 - 并行 - 向每个服务器发送一个查询列表,因为这会减少连接设置时间。但是主体是相同的。)
这是一个非常简单且几乎无限可扩展的问题解决方法,我认为面试官会很高兴听到这个问题。并行排序要困难得多,在这种情况下,复杂性是完全没必要的。
当然,你可能会有一个很好的论据支持你自己的首选策略,一个好的面试官也会很高兴听到一个好的论点,即使它不是他们以前想过的。优秀的工程师总是愿意讨论好的想法。而这种讨论不能从假设两种不同观念中的一种必须是“愚蠢的”开始。
答案 1 :(得分:1)
由于他们认为nlogn很慢,我们可以假设哈希集少于登录许多不同的条目
错误。哈希表的大小为O(len(A))。这不会使算法花费超过线性预期时间,因为在算法的运行时间中没有散列表大小的乘法因子。
此外,虽然可能发生冲突,但通常假定哈希表具有某种冲突解决策略。碰撞不会产生不正确的结果。