我有一个值列表,它们会增加到最大值然后再次减少(这是一个观察到的高斯/钟形分布)。
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的变体应该有效。什么是最少步骤的算法?
漫长的查找时间是由于真实的测量设备(时间按秒级排列)。
答案 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效果最佳。但是三元搜索基于一些不适合整数的非整数评估函数来削减空间。
如果您不需要精确的结果并且接近近似值,您也可以尝试三元搜索。
答案 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)
渐近地,在不依赖于值的某些属性的情况下,它是最好的。如果“不够好”,请更改low
和high
的表达式,以便更好地匹配您的实际数据。