【发布时间】:2013-12-31 19:03:23
【问题描述】:
比如说,我有一个由 n 个元素组成的排序数组。我想使用二进制搜索在这个数组中找到 2 个不同的键 k1 和 k2。
一个基本的解决方案是分别对它们应用二进制搜索,例如两次调用 2 个键,这会将时间复杂度保持在 2(logn)。
我们能否对不同的 k 个键 k
【问题讨论】:
标签: arrays algorithm search time-complexity
比如说,我有一个由 n 个元素组成的排序数组。我想使用二进制搜索在这个数组中找到 2 个不同的键 k1 和 k2。
一个基本的解决方案是分别对它们应用二进制搜索,例如两次调用 2 个键,这会将时间复杂度保持在 2(logn)。
我们能否对不同的 k 个键 k
【问题讨论】:
标签: arrays algorithm search time-complexity
您完成的每个搜索都可用于细分输入以提高效率。例如,假设与 k1 对应的元素位于索引 i1 处。如果 k2 > k1,您可以将第二次搜索限制为 i1..n,否则将其限制为 0..i1。
最好的情况是您的搜索键也已排序,因此每次新搜索都可以从找到最后一个的地方开始。
【讨论】:
您可以通过走一次共享搜索路径来降低真正的复杂性(尽管它仍然是相同的大 O)。也就是说,开始二进制搜索,直到您所在的元素位于您要查找的两个项目之间。此时,生成一个线程以继续对超出您所在的枢轴元素的范围内的一个元素进行二分搜索,并生成一个线程以继续对您所在的枢轴元素之前的范围内的另一个元素进行二分搜索.返回两个结果。 :-)
编辑:
正如 Oli Charlesworth 在他的评论中提到的,您确实要求提供任意数量的元素。不过,同样的逻辑可以扩展到任意数量的搜索键。这是一个例子:
你有一个这样的搜索键数组:
searchKeys = ['findme1', 'findme2', ...]
您拥有将搜索键映射到找到的值的键值数据结构:
keyToValue = {'findme1': 'foundme1', 'findme2': 'foundme2', 'findme3': 'NOT_FOUND_VALUE'}
现在,按照与本次编辑之前相同的逻辑,您可以在每个线程生成时传递一个“修剪过的”searchKeys 数组,其中键在枢轴处发散。每次找到给定键的值时,都会更新 keyToValue 映射。当没有更多要搜索的范围但 searchKeys 数组中仍有值时,您可以假设找不到这些键,您可以更新映射以某种方式表示这一点(可能是一些 null 类似的值? )。当所有线程都已连接(或使用计数器)时,您返回映射。这里最大的胜利是您不必重复任何两个键可能共享的初始搜索逻辑。
第二次编辑:
正如 Mark 在他的回答中添加的那样,对搜索键进行排序允许您只需要查看键范围中的第一项。
【讨论】:
k 项目。我会更新我的答案。
您可以找到学术文章计算一般情况下不同方案的复杂性,即使用最少的比较次数合并两个长度可能非常不同的排序序列。 http://www.math.cmu.edu/~af1p/Texfiles/HL.pdf 上的论文分析了 Hwang 和 Lin 的最著名的方案之一,并引用了其他方案以及 Hwang 和 Lin 的原始论文。
它看起来很像一个合并,它逐步遍历较小列表的每个项目,沿着较大的列表跳过,步长大小是两个列表大小的比率。如果它发现它在大列表中走得太远,它可以使用二分搜索在它已经跨过的值中找到匹配项。如果它还没有走得足够远,它会再走一步。
【讨论】: