【发布时间】:2020-08-09 03:26:47
【问题描述】:
我正在寻找最佳搜索算法,它返回排序数组中元素的索引 O(log(m)),其中 m 是 k 之前的元素数。
注意: 如果 k 不在数组中,m 是最接近 k 的元素之前的元素数。
我想到了一个搜索,每一步都呈指数增长,不一定从中间开始。
【问题讨论】:
标签: arrays algorithm sorting search time-complexity
我正在寻找最佳搜索算法,它返回排序数组中元素的索引 O(log(m)),其中 m 是 k 之前的元素数。
注意: 如果 k 不在数组中,m 是最接近 k 的元素之前的元素数。
我想到了一个搜索,每一步都呈指数增长,不一定从中间开始。
【问题讨论】:
标签: arrays algorithm sorting search time-complexity
您正在寻找Exponential search。
在指数搜索中,我们将索引从 0 以 2 的幂次方跳跃,直到到达一个值高于我们正在寻找的数字的索引。即让我们说数字在索引 14 我们跳转到索引 16 并停止,因为第 16 个索引中的数字大于我们的数字。时间复杂度为O(log m),因为我们在通过 m 的那一刻停止了 2 的幂。
然后我们在 0 和我们在上一步中停止的索引之间执行二进制搜索。为什么?由于现在上下界之间的数字不超过 2m,所以二分查找的时间复杂度为O(log (2m)),即O(log m),我们就完成了!
伪代码:
exponential_search:
Array A
Key k
1. i = 1
2. while A[i - 1] < k and i <= size of A
2.1. i = i * 2
// Now i is no more than 2 * m
3. perform binary search with k and A between 0 and i
4. return the binary search's result
【讨论】:
首先,让我们尝试使k 的范围尽可能小。我们将查看元素a[0], a[1], a[2], ... a[2 ** i], ...,直到找到大于k 的元素。假设我们停在索引r。那么我们肯定知道,因为数组是有序的,如果k在数组中,那么它的位置m小于r。另一个对时间复杂度至关重要的事实是m > i/2。这是真的,因为在上一步我们查看了a[r/2],它小于k。
如果我们对子数组a[0 ... r] 进行简单的二分搜索,我们将在O(log r) 中找到k。查找r 的总步骤数为O(log r)。由于r > m > r/2,log r > log m > log r - 1 是真的。因此我们可以将O(log r)重写为O(log m),这正是我们所需要的。
这是我在 Python 3 中的解决方案:
def find(a, k):
if a[0] > k:
return -1
r = 1
while r < len(a):
if a[r] > k:
break
r *= 2
if r >= len(a):
if a[-1] < k:
return -1
r = len(a) - 1
l = -1
while r - l > 1:
m = (l + r) // 2
if a[m] < k:
l = m
else:
r = m
if a[r] == k:
return r
else:
return -1
【讨论】:
k,您应该始终停止。