在恒定时间内查找排序列表中的数字是否存在? (面试问题)

时间:2010-06-16 14:48:39

标签: algorithm

我正在学习即将进行的面试,并多次遇到过这个问题(逐字逐句)

  

在N个数字的排序列表中查找或确定数字的不存在,其中数字的范围超过M,M>> N和N大到足以跨越多个磁盘。击败O(log n)的算法;恒定时间算法的奖励积分。

首先,我不确定这是否是真正解决方案的问题。我和我的同事已经对这个问题进行了数周的思考,似乎形成了不良(当然,只是因为我们无法想到解决方案并不意味着没有解决方案)。我会问面试官的几个问题是:

  • 排序列表中是否有重复项?
  • 与磁盘数量和N?
  • 的关系是什么

我考虑过的一种方法是二进制搜索每个磁盘的最小值/最大值,以确定应该保存该号码的磁盘(如果存在),然后对磁盘本身进行二进制搜索。当然,如果磁盘数量很大并且您还有一个已排序的磁盘列表,这只是一个数量级的加速。我认为这会产生某种O(log log n)时间。

至于M>> N暗示,也许如果你知道磁盘上有多少个数字以及范围是什么,你可以在某些时候使用鸽子原理来排除某些情况,但我无法确定一个数量级的改进。 / p>

另外,“恒定时间算法的奖励积分”让我有点怀疑。

此问题的任何想法,解决方案或相关历史记录?

16 个答案:

答案 0 :(得分:26)

由于问题没有说明数字存储的格式,您可以告诉采访者您将假设数字以物理方式存储。例如,每个号码可以写在卡上,每张卡由一个人拥有。 alt text

  

N足够大以跨越多个磁盘

现在,如果您想查找或确定不存在号码,您可以询问这些人您所查找的号码是否在他们持有的卡上。 alt text

如果没有人在N秒内回答,那么这个数字就不存在了。这假设每个人都可以听到你,每个人都知道他们的卡上有多少号码。

我对物理学知之甚少(声速,空气摩擦力,每个人大脑看卡片的时间等)

答案 1 :(得分:15)

奇怪的是,问题是确定一个值的非存在性,而不是存在。

这可能意味着它们引用了Bloom过滤器(http://en.wikipedia.org/wiki/Bloom_filter)。 Bloom过滤器可以告诉您元素是否为:

  • 不存在
  • 或可能存在

答案 2 :(得分:12)

如果仅使用比较,我们有一个Omega(log N)(最差情况)下界(即O(1)是不可能的)。

假设您决定查看数组中的某个位置,那么您的对手可以将该元素放置在更大的数组部分中。

因此,在每个步骤中,至少有一半的元素需要考虑,因此最糟糕的情况是Omega(logn)。

所以你可能需要远离使用比较,以便在最坏的情况下比O(log N)做得更好。

正如其他一些答案所提到的那样,你可以进行概率恒定时间搜索,以合理的概率为你提供正确的答案,例如:使用Bloom Filters。

答案 3 :(得分:8)

通过问题的字母,他们可能正在寻找插值搜索,这是平均情况O(log log n)。是的,在最坏的情况下这是O(n),但可以通过分布知识或使用插值二分搜索来改进。

这将进入M>> N暗示。插值搜索的平均案例分析非常复杂,因此我甚至不会尝试在M>>下进行修改。 N.但概念性的,在M>>下N并假设均匀分布,您可以假设该值将以初始搜索位置的+/- 1为界,产生O(1)。

实际的实现可以进行一次初始插值,如果搜索值没有限制,则回退到二进制搜索。

不确定如何在这种方法中使用多个磁盘,但是......

答案 4 :(得分:4)

首先看

M>> N不是我想的提示,它只是不鼓励创建一个位图,它会在O(1)时间内直接告诉你数字是否存在。

我认为N跨越多个硬盘的合理假设是,您可以预期不会有更多磁盘的订购量。因为O(1)性能需要2 M 空间,并且如果N跨越多个磁盘,则M跨越>>多个磁盘和2 M 跨度>磁盘比可用的。

此外,它告诉您存储缺少数字的方法效率不高,因为那时您必须存储X数字

X = M - N => X~M(因为M> N)

这是一个更糟糕的情况。

首先看起来你似乎可以证明没有更好的答案。

编辑: 我仍然坚持上述推理,Moron的回答也证明了这一点。然而得出结论,在看了帕特里克的回答后,我认为面试官可能一直在研究这个和其他概率算法(应该在面试问题中注意到这一点)。

答案 5 :(得分:2)

如果我们所能做的就是比较,那么正如上面的海报所指出的那样,我们不能做得比O(log(N))更好。

但是,如果我们对输入分布有更多了解,我们可以做更多的事情。如果(由访调员:)告知数字是连续的,那么O(1)解决方案是可能的。我们正在寻找的第一个元素和元素之间的差异将为我们提供一个我们应该期望找到数字的确切位置。

答案 6 :(得分:2)

由于我们知道数字(M)的范围,我们可以执行插值二进制搜索。而不是将搜索范围平分1/2,将其平分为N /(HI - LO)。结果仍然是O(log N)但具有较低的常数。如果我们知道数据中没有重复项,这种技术效果会更好,而且问题似乎暗示可能是这种情况,但它并不是确定的。

例如,请参阅此博客:Faster than Binary Search

答案 7 :(得分:1)

嗯,据我所知。在这个问题中,您可以利用两个提示。 1.数字分类和2. N& M非常大(N> M)并且M跨越多个磁盘

您可以在此问题中使用一些随机化。不是使用二进制搜索,而是随机选择一个点,然后检查x(要搜索的数字)是否小于或大于当前值。您可以从两端开始并迭代地减小搜索空间的大小。在非常小的迭代中,只有您可以将其缩小到小域,然后您可以应用二进制搜索来提高效率。

答案 8 :(得分:0)

如果您允许自己使用某些元数据,我认为您可以获得更快的查找时间。

设置许多间接块或列表,其元素指向更多间接块/列表。重复,直到达到所需级别的直接块/列表。我们的想法是使用类似于某些文件系统访问其文件数据的方式(直接,间接,双重间接和三重间接块)。对于他们要求的数字范围,很可能需要三个以上的间接。

您正在查找的数字的每个部分都可以引用间接/直接表中的单独索引。最终,您将向下打破搜索范围,以便您可以阅读可能包含或不包含该数字的最终部分。然后,您可以使用您选择的算法搜索最后一部分。

希望这有帮助并且有意义。

免责声明:我将在一分钟内准备午餐,所以我没有完全考虑过这一点 - 这可能是不切实际的。

答案 9 :(得分:0)

这很可能是一个措辞严厉的问题。

如果Bloom过滤器是他们正在寻找的答案,这很可能是没有必要将候选者与潜在的分布式/并行算法元素(多个磁盘)混淆。

假设一个磁盘

一旦构建过滤器,布隆过滤器就是恒定时间操作。但是,为了弥补误报,必须进行二分搜索(甚至插值搜索,如有人建议假设均匀分布)将导致二进制搜索情况下的因子大于常数log(n)。

所以,它是  O(k)+ 1%* log(n)。 O(k)恒定时间检查布隆过滤器。 假设使用布隆过滤器假设1%的错误率(误报),那么很多时候必须进行二进制搜索以确保它确实存在。

我不确定这可以通过摊销分析(不太精通)减少到恒定时间。

答案 10 :(得分:0)

可靠的事实是,任何进行比较的算法都不可能击败log(n)。这意味着恒定时间解决方案无法相互比较数字。在所有情况下,恒定时间解决方案将涉及欺骗。

鉴于此,通过一系列假设可以实现恒定的时间解决方案:

  • 数字是按顺序写的
  • 您确切地知道数字序列的起始位置和结束位置(磁盘偏移量)
  • 所有磁盘大小相同,并且完全相同的位容量
  • 您确切地知道可以将多少位写入磁盘

考虑到这些假设,只需将k乘以数字的位大小即可。寻找该位置(O(1))+偏移并读回正确的位数。

答案 11 :(得分:0)

尚未提及的一个方面是,问题与您正在使用的计算机类型无关。如果每个硬盘恰好连接到自己的CPU上,那么在恒定时间内完成这一操作是微不足道的。

这看起来像是一个警察,但如果这个问题是由进行分布式计算的面试官提出的,那么可能就是他们正在寻找的答案。

答案 12 :(得分:0)

只是一个谦虚的想法。

也许这更像是一个系统问题,而不是算法问题,让我们试着从搜索引擎的角度思考。

假设我有足够的机器将所有已排序的N个整数编入索引,每台机器只保存N个整数中代表K的固定数量K个文档。

因此,对于任何给定的数字X,客户端查询服务器到达搜索节点的网络时间可以被视为恒定时间;搜索节点查找表示编号X的文档的时间也是固定时间,因为每个搜索节点上的文档数量是固定数字K.

因此总时间是恒定的。然而,这或多或少与恩里克提到的相似。

答案 13 :(得分:0)

问题是关于不存在,所以不需要在磁盘中搜索。 我们可以检查数字X是否超出O(1)中所有磁盘的最小和最大范围。 (磁盘数量不变)

bool not_exists=true
for each disk_i in disks:
  not_exists &&= (X <min_element(disk_i)  || X > max_element(disk_i) )
return not_exists

如果结果为真。那么我们可以确定磁盘中没有X. 否则X'可能是'在磁盘中。

答案 14 :(得分:0)

你可以通过检查保存数字的文件大小来解决这个问题,然后创建一个大小大于文件大小的数字(不是说abt int或lar

答案 15 :(得分:0)

我认为问题清楚地表明你给出一个大小为N的列表,例如

const int N = 15;
int xs[N] = {1, 3, 7, 9, 13, 16, 17, 19, 21, 24, 25, 26, 27, 28, 30};

您必须回答单个查询(小于O(logN)),因此您无法进行任何预处理。我相信如果你可以进行摊销,这个问题的措辞会有所不同。

N在实践中可能非常大,所以即使数字N本身也可能需要存储许多磁盘(我读这个问题的方式:)。我认为这只是表示你不能创建一个大小为M的简单查找数组,因为M > N,因此没有意义。

所以,你真的不能做二分法搜索。但是,如您所知,元素的最大可能值为M(假设数据均匀分布),您可以猜测初始位置,从哪里开始二进制搜索。

这基本上是x / M * N,在代码中可能是这样的:

double hint = static_cast<double>(x) / M; // between [0,1)
int m = static_cast<int>(hint * N); // guess the position in xs
// do binary search using m as initial "middle" point.

所以,考虑到假设保持,这个猜测将使算法加速一个很好的常数。但是,时间复杂度仍为O(lgN)