在向量对中搜索

时间:2018-10-13 05:34:21

标签: algorithm

我有一个向量对(datatype = double),其中每个对是(a,b)并且小于b。对于数字x,我想找出向量中对的数目,其中a <= x <= b。

考虑向量大小约为10 ^ 6。

我的方法
对向量对进行排序,并在成对的“ a”上对x执行一次Lower_bound操作,然后从头开始迭代直到我的下界值,并检查满足x <= b的条件的“ b”的值。

时间复杂度
N(LogN),其中N是向量大小。

问题
我必须在这种方法效率低下的大型查询中执行此操作,因此还有什么更好的解决方案可以降低时间复杂度。

对不起,我的英语和问题格式都很差。

4 个答案:

答案 0 :(得分:0)

首先,如果仅对这些对进行简单扫描,则复杂度为O(n)! O(n log n)来自排序,对于一次性操作,这只是开销。这甚至可能是最好的方法,如果您不重用结果,即使您仅执行一些查询,它仍可能比排序更好。确保您允许自己退出算法。

无论如何,让我们考虑您需要进行许多查询。然后,进行改进的一个相对明显的步骤是在排序后不逐步进行迭代。相反,您可以对下限进行二进制搜索。只需将序列分成两半即可。下限可以在任意一半中找到,您可以通过查看分区之间的中间元素来确定。递归直到找到第一个元素(该元素可能不包含搜索的值),因为它的起始值已经更大。

关于另一个方向,事情并不是那么容易。仅仅因为您按起始值对范围进行了排序,并不意味着也对结束值进行了排序。此外,可以在序列中混合匹配范围和不匹配范围,因此在这里您将必须执行线性扫描。

最后,一些注意事项:

  • 您可以使用多线程并行化此算法。
  • 根据外部循环中的搜索数M,也可以将内部循环与外部循环切换。这意味着对于每对输入矢量,您都要检查M个搜索值中的每一个是否都在该范围内。这样做可能会更好,特别是当M搜索适合CPU缓存时。

答案 1 :(得分:0)

对于段树,二进制索引树,间隔树,这是一个非常典型的样式问题。

必须对数组arr进行两项操作。

您在数组arr上有两个操作:
1. 范围更新Add(a, b): for(int i = a; i <= b; ++i) arr[i]++
2. 点查询Query(x): return arr[x]

或者,您可以巧妙地提出问题。
1. 点更新Add(a, b): arr[a]++; arr[b+1]--;
2. 范围查询Query(x): return sum(arr[0], arr[1] ..... arr[x]);

在以上每种情况下,您都有一个O(n)运算和一个O(1)运算。

对于第二种情况,查询本质上是前缀总和计算。二叉索引树在此任务上特别有效。

Tutorial for Binary Indexed Trees

重要思想:阵列压缩

您确实提到向量的大小约为10^6,因此有可能无法创建那么大的数组。如果您可以事先创建一个由所有abx组成的集合,则可以将它们转换为从1到{ {1}}。

超级聪明的想法:MO的算法

仅当允许您离线解决问题时,才允许这样做。这意味着您可以将所有查询点size of set用作输入,以任意顺序解决它们并存储解决方案,然后以正确的顺序打印解决方案。

如果您的情况如此,请提及,然后我将进一步详细说明。但是二叉索引树将比Mo算法更有效。

编辑:

由于间隔值的类型为x,因此在使用我的解决方案之前必须将其转换为整数。让我举个例子

double

这里所有有趣的点都不都是可能的双打,而只是上述数字 Intervals = (1.1 to 1.9), (1.4 to 2.1) Query Points = 1.5, 2.0

如果我们将它们映射为正整数:

= {1.1, 1.4, 1.5, 1.9, 2.0, 2.1}

然后,您可以使用段树/二进制索引树。

答案 2 :(得分:0)

除了前面的答案外,这里还建议如何准备范围以优化后续查找。这个想法可以归结为对所有明显不同的输入值预先计算结果,但是要知道何时值没有明显不同。

为说明我的意思,让我们考虑以下范围的顺序:

1, 3
1, 8
2, 4
2, 6

准备好的输出结构如下:

1, 2 -> 2
2, 3 -> 4
3, 4 -> 3
4, 6 -> 2
6, 8 -> 1

对于1, 2范围内的任何数字,初始序列中都有两个匹配范围。对于2, 3范围内的任何数字,有四个匹配项,以此类推。请注意,由于某些输入范围部分重叠,因此这里有五个范围。由于此处的每个范围的最终值也是下一个范围的初始值,因此可以优化最终值。然后结果看起来像一个简单的地图:

1 -> 2
2 -> 4
3 -> 3
4 -> 2
6 -> 1
8 -> 0

请注意,最后一个范围没有后面的一个,因此显式零是必要的。对于第一个之前的值,这是隐含的。为了找到某个值的结果,只需找到小于或等于该值的键即可。这是一个简单的O(log n)查找。

答案 3 :(得分:-1)

对于每对a,b,您都可以分解,使得对于特定值有效的范围数为a = + 1和b = -1。然后,in变成一个简单的O(log n)查找,以查看有多少范围包含搜索值。