check if there exists a[i] = 2*a[j] in an unsorted array a?

匿名 (未验证) 提交于 2019-12-03 08:46:08

问题:

Given a unsorted sequence of a[1,...,n] of integers, give an O(nlogn) runtime algorithm to check there are two indices i and j such that a[i] =2*a[j]. The algorithm should return i=0 and j=2 on input 4,12,8,10 and false on input 4,3,1,11.

I think we have to sort the array anyways which is O(nlogn). I'm not sure what to do after that.

回答1:

You're right that the first step is sorting the array.

Once the array is sorted, you can find out whether a given element is inside the array in O(log n) time. So if for every of the n elements, you check for the inclusion of another element in O(log n) time, you end up with a runtime of O(n log n).

Does that help you?



回答2:

Note: that can be done on 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 

Proof:
=>
If there are 2 elements a[i] and a[j] such that a[i] = 2 * a[j], then when iterating first time, we inserted 2*a[j] to the set when we read a[j]. On the second iteration, we find that a[i] == 2* a[j] is in set, and return true.

<=
If the algorithm returned true, then it found a[i] such that a[i] is already in the set in second iteration. So, during first itetation - we inserted a[i]. That only can be done 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:
In order to return the indices of the elemets, one can simply use a hash-map instead of a set, and for each i store 2*a[i] as key and i as value.

Example:
Input = [4,12,8,10]

first insert for each x - 2x to the hash table, and the index. You will get:

hashTable = {(8,0),(24,1),(16,2),(20,3)}

Now, on secod iteration you check for 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. 

so, final output is 2,0 - as expected.


(1) Complexity notice:
In here, O(n) assumes O(1) hash function. This is not always true. If we do assume O(1) hash function, we can also assume sorting with radix-sort is O(n), and using a post-processing of O(n) [similar to the one suggested by @SteveJessop in his answer], we can also achieve O(n) with sorting-based algorithm.



回答3:

  1. Sort the array (O(n log n), or O(n) if you're willing to stretch a point about arrays of fixed-size integers)
  2. Initialise two pointers ("fast" and "slow") at the start of the array (O(1))
  3. Repeatedly:
    1. increment "fast" until you find an even value >= twice the value at "slow"
    2. if the value at "fast" is exactly twice the value at "slow", return true
    3. increment "slow" until you find a value >= half the value at fast
    4. if the value at "slow" is exactly half the value at "fast", return true
  4. if one of the attempts to increment goes past the end, return false

Since each of fast and slow can be incremented at most n times total before reaching the end of the array, the "repeatedly" part is O(n).



回答4:

  1. Create an array of pairs A={(a[0], 0), (a[1], 1), ..., (a[n-1], n-1)}
  2. Sort A,
  3. For every (a[i], i) in A, do a binary search to see if there's a (a[i] * 2, j) pair or not. We can do this, because A is sorted.

Step 1 is O(n), and step 2 and 3 are O(n * log n).

Also, you can do step 3 in O(n) (there's no need for binary search). Because if the corresponding element for A[i] is at A[j], then then corresponding element for A[i+1] cannot be in A[0..j-1]. So we can keep two pointers, and find the answer in O(n). But anyway, the whole algorithm will be O(n log n) because we still do sorting.



回答5:

Sorting the array is a good option - O(nlogn), assuming you don't have some fancy bucket sort option.

Once it's sorted, you need only pass through the array twice - I believe this is O(n)

Create a 'doubles' list which starts empty.

Then, For each element of the array:

  • check the element against the first element of the 'doubles' list
    • if it is the same, you win
    • if the element is higher, ditch the first element of the 'doubles' list and check again
  • add its double to the end of the 'doubles' list

  • keep going until you find a double, or get to the end of your first list.



回答6:

You can also use a balanced tree, but it uses extra space but also does not harm the array.

Starting at i=0, and incrementing i, insert elements, checking if twice or half the current element is already there in the tree.

One advantage is that it will work in O(M log M) time where M = min [max{i,j}]. You could potentially change your sorting based algorithm to try and do O(M log M) but it could get complicated.

Btw, if you are using comparisons only, there is an Omega(n log n) lower bound, by reducing the element distinctness problem to this:

Duplicate the input array. Use the algorithm for this problem twice. So unless you bring hashing type stuff into the picture, you cannot get a better than Theta(n log n) algorithm!



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!