n個のアイテムのtop-mを取得するためのO(n log m)の複雑さを提供する、提案された「ヒープの上部をのぞく」アルゴリズムに加えて、さらに2つのソリューションがあります。
解決策1:フィボナッチヒープを使用します。
JDKのPriorityQueueの実装は、バランスの取れたバイナリヒープです。フィボナッチヒープの実装からより多くのパフォーマンスを引き出すことができるはずです。一定時間の挿入は償却されますが、バイナリヒープへの挿入は、ヒープのサイズが複雑さΩ(log n)になります。すべての要素に対してこれを実行している場合は、Ω(n log n)になります。Fibヒープを使用してn個のアイテムの上位mを見つけるには、複雑さO(n + m log n)があります。これを、ヒープにm個の要素のみを挿入するという提案と組み合わせると、O(n + m log m)が得られます。これは、取得する線形時間に非常に近い値です。
解決策2:リストをM回トラバースします。
O(n)時間でセット内のk番目に大きい要素を取得できるはずです。すべてをリストに読み込んで、次の手順を実行するだけです。
kthLargest(k, xs)
Pick a random pivot element p from the list
(the first one will do if your list is already random).
Go over the set once and group it into two lists.
Left: smaller than p.
Right: Larger or equal to p.
If the Right list is shorter than k, return kthLargest(k - right.size, Left)
If the Right list is longer than k, return kthLargest(k, right)
Otherwise, return p.
それはあなたにO(n)時間を与えます。そのm回実行すると、時間O(nm)でセット内の上位m個のオブジェクトを取得できるはずです。これは、nが十分に大きくmが十分に小さい場合はnlognよりも厳密に小さくなります。たとえば、100万を超えるアイテムのトップ10を取得するには、バイナリヒープ優先キューを使用する場合の半分の時間がかかります。他のすべての条件は同じです。