这不使用线性散列, 但工作速度比 O( N2 更快 ) :
- Choose some small number C and use a brute-force algorithm to find first duplicate for the first C elements of the array. Clear first C elements if nothing found yet.
- Perform the remaining steps with first N elements empty. Initially, N=C. After each iteration, N is doubled.
- Sequentially add numbers from indexes N+1 .. 3*N/2 to the hash table in first N array elements. Use open addressing. After all N/2 elements moved, hash load factor should be 1/2. Clear space, occupied by N/2 elements we just moved. For the next N/4 elements, search each of them in the hash table(s), constructed so far, then hash them to the space which is always twice as much as number of elements. Continue this until N-C array elements are hashed. Search the remaining C elements in the hash tables and compare them to each other.
- Now we have N array elements without duplicates, occupying 2*N space. Rehash them in-place.
- Sequentially search all other elements of the array in this hash table. Then clear these 2*N elements, set N=2*N, and continue with step 3.
步骤 3. 5 可简化。 只有散列元素 N+1. 3*N/2 并在此散列表格中搜索数组的所有其他元素。 然后对元素 3* N/2+1. 2* N. 这比原始算法慢两倍, 但平均还是 O(Nlog N) 。
其它的替代方案是使用第一个 N 空元素来构造元素 N+1 的二进制搜索树。 3* N/2 并搜索此树中数组的所有其他元素。 然后对元素 3* N/2+1. 2 * N. (只有在数组足够小且其元素可以用整数值索引的情况下才能使用此功能 ) 。
上文描述的 Algorithm 是概率性的, 平均在 O( Nlog N) 时间工作。 最差的情况复杂度是 O( N < supp> 2 sup > ) 。 使用二进制搜索树的替代办法可能是 O( Nlog < sups > 2 sup> N) 最差的情况复杂度, 如果树是自平衡的, 情况复杂。 但是这很复杂 。 在 O( N log < supp > 2 sup> N) 最差的情况复杂时, 可以用更简单的算法来完成任务 。
此算法通过数组顺序迭代, 并保留以下变量: 最大可能的子数组, 大小为二分之一, 适合当前位置左侧, 开始于索引 0 并进行分类; 下一个次数组跟随它, 并且也进行分类 。 换句话说, 当前指数的二进制表达方式描述它之前有多少次数排序 。 例如, 87 指数 ( 1010111) 在指数 86 上有一个单项元素, 在指数 84 上对一对进行分类, 分类为 80 的 4 个次数组, 分类为 64 的 16 个次数组, 在数组开始时有 64 个次数组元素 。
- Iterate through the array
- Search current element in all preceding sub-arrays using binary search.
- Sort current element together with those preceding sub-arrays, that correspond to trailing "ones" in the binary representation of current index. For example, for index 87 (1010111), we need to sort current element together with 3 sub-arrays (1+1+2+4=8 elements). This step allows adding current element to sub-arrays while keeping algorithm s invariant.
- Continue with next iteration of step 1.