C++ 在具有非递减连续差的排序数组中,以O(log(log(max_值))为单位查找小于X的最大元素
我想找到排序数组中小于C++ 在具有非递减连续差的排序数组中,以O(log(log(max_值))为单位查找小于X的最大元素,c++,algorithm,sorting,lower-bound,C++,Algorithm,Sorting,Lower Bound,我想找到排序数组中小于x的最大元素,其中数组中连续元素之间的差异不递减 例如: [1,3,10,17,50,1000]是有效的输入,因为连续的差异(2,7,7,33950)是按递增顺序排列的 [1,3,4,10,18]不是有效的输入,因为连续的差异(2,1,6,8)不是递增顺序 最佳解决方案是O(log(log max_value)),因此我正在寻找比上限/二进制搜索更好的解决方案。实际上,我希望优化二进制搜索,从O(logn)到O(logmax\u值) #包括 使用名称空间std; 常数int
x
的最大元素,其中数组中连续元素之间的差异不递减
例如:
[1,3,10,17,50,1000]
是有效的输入,因为连续的差异(2,7,7,33950)
是按递增顺序排列的
[1,3,4,10,18]
不是有效的输入,因为连续的差异(2,1,6,8)
不是递增顺序
最佳解决方案是O(log(log max_value))
,因此我正在寻找比上限/二进制搜索更好的解决方案。实际上,我希望优化二进制搜索,从O(logn)
到O(logmax\u值)
#包括
使用名称空间std;
常数int n=50000001;
int-arr[n];
int-binarysearch\u lowerbound(int-begin、int-end、int-x)
{
int ans=结束;
while(开始<结束){
int mid=(开始+结束)/2;
如果(arr[mid]>=x){
ans=中等;
结束=中间;
}
否则{
开始=中间+1;
}
}
返回ans;
}
int main()
{
int N;
cin>>N;
对于(int i=0;i>arr[i];
}
int-q;
cin>>q;
对于(int i=0;i>x;
int k;
int begin=x/(arr[N-1]-arr[N-2]);
int end=x/(arr[1]-arr[0]);
如果(结束>N-1){
end=N;
}
k=二进制搜索\u lowerbound(开始、结束、x);
cout要得到O(logn),可能需要使用插值搜索而不是二进制搜索
在插值搜索中,获取要查找的值以及数组中的最小值和最大值,并根据它们猜测要查找的元素的可能位置,而不是盲目猜测数组未知部分的中间位置
简单的情况是,元素在阵列中大致均匀分布,在这种情况下,可以使用线性插值来猜测要搜索的点
在你的例子中,数据遵循一个绝对非线性的分布,因此你要基于此预测位置,而不是线性插值。作为第一近似值,我们假设它大致是二次的
对于第一个测试,让我们从一组精确遵循二次分布的数字开始:[1,4,9,16,25,36,49,64]。我们将搜索小于30的最大值。我们的集合有8个值,范围为1..64=63
如果我们使用线性插值来搜索30,我们的初始猜测将是30/63*8=3或4(在这种情况下,这实际上相当准确)
要进行二次插值,我们首先取范围顶部和底部的平方根(分别为8和1),然后取30(~5.5)的平方根,然后用这些平方根(5.5/(8-1)*8)进行线性插值,以得到我们的初始猜测
从这里开始,我们继续进行二元搜索——如果我们的数字大于我们找到的值,我们在较大的数字之间进行新的插值,如果较小,我们在较小的数字之间进行新的插值
所有这些中最困难的部分是找到一个能很好地拟合你的数字的函数。在你的例子中,这可能特别有问题,因为你只得到了关于分布的一点点信息。要求差异不能减少意味着它至少是线性的,但除此之外,我们真的没有知道——它可能是线性的,或者N1.1,或者N10,甚至可能是类似于N的东西。线性插值不能很好地拟合阶乘分布(反之亦然).我被问题陈述弄糊涂了。最大的元素只是排序范围的最后一个元素。你想检查相邻的差异是否在增加吗?请给出一些输入/输出示例。数组的最大元素,小于给定值XSo,有什么问题?极端情况[0,1,2,3,4,5,6,7,8,9,10]
将是一个有效的输入,因为示例显示要求不是差异在增加。它只是不允许减少,对吗?@Ted Lyngmo是的,你是对的。我在想,检查第一个和最后一个元素不会给出用于查找下一个要比较的元素的函数的大致概念吗?对于e每检查一个新元素,就会形成一个新函数。@TedLyngmo:第一个和最后一个自己不会。仅从两点就可以得出的最佳猜测是线性分布。第一个、中间和最后一个会告诉你更多。啊,有道理,谢谢。你的解释很有帮助,我不知道如何插值search、 给出了一个提示或子问题,其中连续差值为100到200。牛顿-拉斐逊肯定给出了O(loglogn)
,而没有假设分布的二次性。
#include <bits/stdc++.h>
using namespace std;
const int n = 50000001;
int arr[n];
int binarysearch_lowerbound(int begin, int end, int x)
{
int ans = end;
while (begin < end) {
int mid = (begin + end) / 2;
if (arr[mid] >= x) {
ans = mid;
end = mid;
}
else {
begin = mid + 1;
}
}
return ans;
}
int main()
{
int N;
cin >> N;
for (int i = 0; i < N; i++) {
cin >> arr[i];
}
int q;
cin >> q;
for (int i = 0; i < q; i++) {
int x;
cin >> x;
int k;
int begin = x / (arr[N - 1] - arr[N - 2]);
int end = x / (arr[1] - arr[0]);
if (end > N - 1) {
end = N;
}
k = binarysearch_lowerbound(begin, end, x);
cout << arr[k - 1] << endl;
}
return 0;
}