我有一个大小为 n 的数组 arr ,其中包含以随机顺序排列的整数1到 n ;例如,它可能是arr = [4 5 3 6 2 1]
。
对于 arr 中的每个元素 e ,我需要找到小于 e k >。 ("最接近"就位置而言,而不是价值;所以在上面的例子中,5更接近于3而不是6)。如果在两个方向上有相同的近似较小的元素 - 就像在6中一样上面的例子,其直接邻居都小于它 - 那么选择这些元素中的哪一个并不重要。
因此,通过上面的示例arr = [4 5 3 6 2 1]
,一个有效的结果是[3 3 2 2 1 NIL]
。
我知道有一个O( n )算法来解决这个问题;它通过维护一个堆栈来找到每个元素左右两侧最近的较小元素。
但令人惊讶的是,简单的线性双向搜索比该算法表现更好,即使在最坏的情况下我似乎是O( n 2 ): / p>
for i = 1 to N
right = i + 1
left = i - 1
while (left > 0 && right <= n)
// ...find the closest element that is smaller than arr[i] and break while loop
上述情况的最坏情况是什么?我是对的O( n 2 )?
答案 0 :(得分:1)
这是最坏情况Θ( n log n )时间(假设你实现了Daniel上面提到的修复 - 你需要确保你可以扫描所有每个方向的结束方式)。
首先,观察如果两个元素 a 和 b 是邻居,那么 a &lt; b 或 b &lt; 一。在任何一种情况下,这些元素中的至少一个将需要仅“1”的“搜索距离”。
通过扩展,至少有一半的数组元素需要的搜索距离仅为1。
同样,如果四个元素[ a , b , c , d ]都在一行中,其中一个比其他三个少。因此,这些元素中至少有三个需要最多3个搜索距离。如上所述,其中两个实际上只需要1的搜索距离,所以这意味着两个搜索距离为1,第三个搜索距离为1。搜索距离最多为3.总搜索距离最多为2·1 + 1·3 +( n -1)。
我们可以继续这个逻辑来增加长度2 k 的运行:我们最多有2个 k -1 ·(2 1 -1)+ 2 ķ -2 ·(2 2 -1)+ 2 ķ -3 ·(2 3 -1)+⋯+(名词 -1)。
如果 n 是2的幂,那么我们可以将其写为2 k ,总搜索距离最多为:
2 ķ -1 ·(2 1 -1)+ 2 ķ -2 ·(2 2 -1)+ 2 ķ -3 ·(2 3 -1)+⋯ + 2 0 ·(2 ķ -1)=
=(2 ķ -2 ķ -1 )+(2 ķ -2 ķ -2 )+(2 ķ -2 < EM>ķ -3 )+⋯+(2 ķ -2 0 )
= k ·2 k - 2 k + 1
= n log n - log n + 1
&LT; n log n
(如果 n 不是2的幂,那么我们可以通过附加值 n +1来获得更大的数组, n +2等,直到我们确实具有2的幂,并且观察到所得到的总搜索距离小于2
当然,上面只设置了一个上限( O 而不是Θ);但我认为它显示了如何真正实现最坏情况:我们希望尽可能多地以尽可能多的方式传播,以两种方式。例如,我们可以“扩展”这样的列表:
1 2
1 3 2 4
1 5 3 6 2 7 4 8
如上所述,上述搜索总距离为7 + 1 + 2 + 1 + 4 + 1 + 2 + 1 = 17 = 3·8 - 8 + 1。