Note: what can be done in O(n)
1 on average using a hash table.
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
Evidence:
=>
If there are 2 elements a[i]
and a[j]
such that a[i] = 2 * a[j]
, then at the first iteration we insert 2*a[j]
into the set when we read a[j]
. In the second iteration, we find that a[i] == 2* a[j]
is in the set and returns true.
<=
If the algorithm returned true, then he found a[i]
in such a way that a[i]
already in the set at the second iteration. So, during the first iteration, we inserted a[i]
. This can be done only if there is a second element a[j]
such that a[i] == 2 * a[j]
, and we inserted a[i]
when reading a[j]
.
Note:
To return element indices, you can simply use a hash map instead of a set, and for each i
save 2*a[i]
as a key and i
as a value.
Example:
Input = [4,12,8,10]
first insert for each x - 2x hash table and index. You'll get:
hashTable = {(8,0),(24,1),(16,2),(20,3)}
Now, in the iteration of secod, you check each element if it is in the table:
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.
therefore, the final result is 2.0 - as expected.
(1) Notification of difficulty:
Here O(n)
takes an O(1)
hash function. This is not always true. If we accept the hash function O(1)
, we can also assume that sorting using radix-sort is O(n)
, and using post-processing O(n)
[similar to the one suggested by @SteveJessop in his answer ], we can also achieve O(n)
using a sorting algorithm.