说,我有一个n元素的排序数组。我想使用二进制搜索在这个数组中找到2个不同的键k1和k2。
一个基本的解决方案是分别对它们应用二进制搜索,比如两次调用2个键,这会将时间复杂度保持在 2(logn)。
我们可以使用任何其他方法针对不同的k个密钥来解决这个问题,k< n?
答案 0 :(得分:3)
您完成的每个搜索都可用于细分输入以提高效率。例如,假设对应于k1的元素在索引i1处。如果k2> k1你可以将第二次搜索限制为i1..n,否则将其限制为0..i1。
最好的情况是您的搜索键也被排序,因此每个新搜索都可以从找到最后一个搜索键开始。
答案 1 :(得分:1)
通过一次走共享搜索路径,您可以降低真实的复杂性(尽管它仍然是相同的大O)。也就是说,启动二进制搜索,直到您所在的元素位于您要查找的两个项目之间。此时,生成一个线程以继续二进制搜索在您所在的枢轴元素之后的范围内的一个元素,并生成一个线程以继续二进制搜索该枢轴元素之前的范围中的另一个元素。返回两个结果。 : - )
修改强>
正如奥利查尔斯沃思在评论中提到的,你确实要求任意数量的元素。但是,相同的逻辑可以扩展到任意数量的搜索键。这是一个例子:
您有一系列搜索键,如下所示:
searchKeys = ['findme1', 'findme2', ...]
您拥有将搜索键映射到找到的值的键值数据结构:
keyToValue = {'findme1': 'foundme1', 'findme2': 'foundme2', 'findme3': 'NOT_FOUND_VALUE'}
现在,遵循与此EDIT之前相同的逻辑,您可以在每个线程spawn上传递一个“pruned”searchKeys
数组,其中键在枢轴处发散。每次找到给定键的值时,都会更新keyToValue
地图。当没有更多范围要搜索但仍然在searchKeys
数组中的值时,您可以假设找不到这些键,您可以更新映射以某种方式表示(某些null
- 喜欢价值吗?)。当所有线程都已连接(或使用计数器)时,您将返回映射。这里的最大胜利是你不必重复任何两个键可能共享的初始搜索逻辑。
第二次编辑:
正如马克在答案中补充的那样,对搜索键进行排序后,您只需要查看关键范围内的第一项。
答案 2 :(得分:1)
您可以找到计算一般情况的不同方案的复杂性的学术文章,其使用最小数量的比较来合并两个可能非常不同长度的排序序列。 http://www.math.cmu.edu/~af1p/Texfiles/HL.pdf的论文分析了Hwang和Lin提到的最着名的方案之一,并参考了其他方案,以及Hwang和Lin的原始论文。
它看起来很像合并,它逐步遍历较小列表的每个项目,沿着较大的列表跳过一个步长,即两个列表的大小比例。如果它发现它已经沿着大列表走得太远,它可以使用二进制搜索来找到它已经跨越的值之间的匹配。如果它没有走得足够远,那就需要另一步了。