给定一个[1,...,n]整数的未排序序列,给出一个O(nlogn)运行时算法来检查有两个索引i和j,使a [i] = 2 * a [j ]。该算法应在输入4,12,8,10上返回i = 0和j = 2,在输入4,3,1,11上返回false。
我认为无论如何我们必须对数组进行排序,即O(nlogn)。我不知道在那之后该怎么办。
答案 0 :(得分:12)
注意:可以使用hash table平均在O(n)
1 上完成。
set <- new hash set
for each x in array:
set.add(2*x)
for each x in array:
if set.contains(x):
return true
return false
<强>证明:强>
=&GT;
如果有2个元素a[i]
和a[j]
,那么a[i] = 2 * a[j]
,那么当我们第一次迭代时,我们在读{{1}时将2*a[j]
插入到集合中}}。在第二次迭代中,我们发现a[j]
已设置,并返回true。
&LT =
如果算法返回true,则它找到a[i] == 2* a[j]
,使得a[i]
已经在第二次迭代中的集合中。因此,在第一次启动时 - 我们插入了a[i]
。只有在存在a[i]
的第二个元素a[j]
时才能执行此操作,并且在阅读a[i] == 2 * a[j]
时我们插入了a[i]
。
注意:强>
为了返回元素的索引,可以简单地使用哈希图而不是集合,并且对于每个a[j]
商店i
作为关键字和2*a[i]
作为价值。
示例:强>
i
首先为每个x - 2x插入哈希表和索引。你会得到:
Input = [4,12,8,10]
现在,在secod迭代中,检查每个元素是否在表中:
hashTable = {(8,0),(24,1),(16,2),(20,3)}
所以,最终输出是2.0 - 正如预期的那样。
(1)复杂性通知:
在这里,arr[0]: 4 is not in the table
arr[1]: 12 is not in the table
arr[2]: 8 is in the table - return the current index [2] and the value of 8 in the map, which is 0.
假设O(n)
哈希函数。这并非总是如此。如果我们假设O(1)
哈希函数,我们也可以假设使用radix-sort进行排序O(1)
,并使用O(n)
的后处理[类似于@SteveJessop建议的那个]他的答案],我们也可以通过基于排序的算法实现O(n)
。
答案 1 :(得分:10)
O(n log n)
或O(n)
进行排序)O(1)
)初始化两个指针(“fast”和“slow”)fast
由于fast
和slow
中的每一个都可以在到达数组末尾之前最多增加n
次,因此“重复”部分为O(n)
。< / p>
答案 2 :(得分:8)
你是对的,第一步是对数组进行排序。
对数组进行排序后,您可以在O(log n)
时间内查明给定元素是否在数组内。因此,如果对于每个n
元素,检查是否在O(log n)
时间内包含了另一个元素,则最终会得到O(n log n)
的运行时。
这对你有帮助吗?
答案 3 :(得分:1)
步骤1是O(n),步骤2和3是O(n * log n)。
此外,您可以在O(n)中执行第3步(不需要二进制搜索)。因为如果A [i]的对应元素是A [j],那么A [i + 1]的对应元素不能在A [0..j-1]中。所以我们可以保留两个指针,并在O(n)中找到答案。但无论如何,整个算法将是O(n log n)因为我们仍然进行排序。
答案 4 :(得分:0)
对数组进行排序是一个很好的选择--O(nlogn),假设你没有一些奇特的桶排序选项。
一旦它被排序,你只需要两次通过数组 - 我相信这是O(n)
创建一个“双打”列表,该列表从空开始。
然后,对于数组的每个元素:
将其双精度添加到“双打”列表的末尾
继续前行,直至找到双倍,或者到达第一个列表的末尾。
答案 5 :(得分:0)
您也可以使用平衡树,但它使用额外的空间,但也不会损坏数组。
从i=0
开始,并递增i
,插入元素,检查树中是否存在当前元素的两倍或一半。
一个优点是它可以在O(M log M)
M = min [max{i,j}]
时间内工作。您可能会更改基于排序的算法以尝试执行O(M log M)
但它可能会变得复杂。
顺便说一句,如果你只使用比较,那么通过将元素清晰度问题减少到这个,有Omega(n log n)
下限:
复制输入数组。将此算法用于此问题两次。因此,除非您将散列类型的内容添加到图片中,否则您无法获得比Theta(n log n)
算法更好的内容!