用于在钟形值列表中查找最大值的快速算法

时间:2016-11-19 16:01:09

标签: algorithm binary-search hill-climbing

我有一个值列表,它们会增加到最大值然后再次减少(这是一个观察到的高斯/钟形分布)。

values = [0, 4, 5, 15, 30, 20, 10, 5, 0];

但是分配也可以改变:

values = [0, 0, 0, 1, 2, 3, 8, 15, 30];

或类似地:

values = [30, 20, 5, 2, 1, 1, 0, 0, 0];

在此特定应用程序中确定特定索引处的值非常昂贵,因此使用尽可能少的数组查找非常重要。

hill climbing等解决方案或binary search的变体应该有效。什么是最少步骤的算法?

漫长的查找时间是由于真实的测量设备(时间按秒级排列)。

3 个答案:

答案 0 :(得分:1)

假设您没有局部最大值(正如测量时通常会发生的那样),二进制查找是最快的方法。如果你有1000个数据点,那么在最坏的情况下,当最大值出现在中间位置时,最终会得到大约10次检查。

要应对数据右侧或左侧最大值的情况(如第二个和第三个示例中所示),您可以先检查两端中的任何一个是否高于其连续点如果确实如此,您最终只需要两次检查即可结束搜索。

答案 1 :(得分:1)

正如FDavidov所提到的,你应该使用二进制搜索的变体,因为在最坏的情况下你只需要访问ceil[O(logn)]个索引。

二进制搜索变体的伪代码如下所示:

left := 0
right := n - 1
while left < right do
    mid := left + (right - left) / 2
    if values[mid] > values[mid + 1] 
         right := mid
    else
         left := mid 
end

print left

但是,要在非凸形图中找到最大或最小点,ternary search效果最佳。但是三元搜索基于一些不适合整数的非整数评估函数来削减空间。

如果您不需要精确的结果并且接近近似值,您也可以尝试三元搜索。

enter image description here

答案 2 :(得分:1)

您正在寻找三元搜索,可能还有插值搜索的一些启发式方法。

基本上,从

开始
def search(f, begin, end):
    if end - begin <= 3:
        return max(map(f, range(begin, end)))
    low = (begin * 2 + end) / 3
    high = (begin + end * 2) / 3
    if f(low) > f(high):
        return search(f, begin, high - 1)
    else:
        return search(f, low + 1, end)

渐近地,在不依赖于值的某些属性的情况下,它是最好的。如果“不够好”,请更改lowhigh的表达式,以便更好地匹配您的实际数据。