重複を効率的に、少ないメモリオーバーヘッドで削除する


9

結果セットのみを格納する必要があるように、重複の整数のリストを効率的にフィルター処理したいと思います。

これを確認できる1つの方法:

  • 整数の範囲、大きい(たとえば)S={1,…,N}N240
  • 関数があり、衝突が多いと思われます(画像はに均一に分布しています)。f:S→SS
  • 次に、を格納する必要があり。つまり、f[S]{f(x)|x∈S}

かなり正確な(確率的)推定値がありであるため、事前にデータ構造を割り当てることができます()。| f [ S ] | ≈ 2 30|f[S]||f[S]|≈230

私はいくつかのアイデアを持っていますが、何が最善のアプローチになるかわかりません:

  • 入力セットがメモリに収まらないため、ビットセットは問題外です。
  • ハッシュテーブルですが、(1)メモリオーバーヘッドが必要です|f[S]|(2)作成時にテーブルを調査する必要があり、メモリのオーバーヘッドのために追加の時間が必要です。
  • 「オンザフライ」ソート、できれば複雑度(非比較ソート)。それに関して、バケットソートとフラッシュソートの主な違いは何なのかわかりません。O(N)
  • 二分探索木を持つ単純な配列ですが、これには時間必要です。O(Nlog⁡|f[S]|)
  • ブルームフィルターまたは同様のデータ構造を使用すると、問題の緩和(誤検知を伴う)に役立つ可能性があります。

stackoverflowの上のいくつかの質問は、物事のこの種に取り組むように見える(/programming/12240997/sorting-array-in-on-run-time、/programming/3951547/java -array-finding-duplicates)、しかし私の要件に一致するものはないようです。


2
f [S](それが何であれ)を列挙する必要がありますか、それともxが含まれているかどうかをすばやく確認できるようにする必要がありますか?
— Gilles「SO-邪悪なことをやめ

@ギレス:f [S]には明らかな構造がないため、2つのソリューションは同等であると私は信じています。
— ドキュメント

あなたの数は足し合わない。サイズドメインのランダム関数の予想されるイメージは、おおよそ(1 − 1 / e )Nです。もう1つの問題は、2 56を通過するのに、スーパーコンピュータまたは大規模なクラスターを自由に使用できない場合、時間がかかりすぎることです。N(1−1/e)N256
— Yuval Filmus

1
二分探索木の時間はであり、実際にはO (N log N )に近い場合とそうでない場合がありますが、より正確です。O(Nlog⁡|f[S]|)O(Nlog⁡N)
— jmad

1
、線形時間アルゴリズムは、あまりにも法外ではないでしょうか?(私の計算から、1ナノ秒でSの 1つの要素を考慮したとしても、2年はかかります!)N∼256S
— Aryabhata 2012

回答:


1

なぜビンとチェーンではないのですか?

アイデアは、によって表現正の整数を格納することでアレイ内のビットAの2 k個の値の範囲を表すエントリ:エントリA [ Y ]、Y ≥ 0、範囲を表す[ 2 m個の Yを、2 M(Y + 1 )− 1 ]。いずれかのための1 ≤ X < 2 N我々は書き込むことができ、X = 2 m個の Yn=k+mA2kA[y]y≥0[2my,2m(y+1)−1]1≤x<2nここで、 yは kビット、 zは mビットです。場所 yにz( xではなく!)を保存してみます。x=2my+zykzmzxy

  • 場合、何もしない:xは重複です。A[y]=zx

  • 場合初期化されていない、店舗ZでA [ Y ]。A[y]zA[y]

  • それ以外の場合は、リンクされたリスト内の(yで衝突した)をチェーンするために使用される個別の配列にインデックスを格納します。A [ y ]で始まるリストを直線的に検索する必要があり、検索の結果によっては、リストにzが挿入される可能性があります。zyA[y]z

最後に、は、Aの初期化されたエントリをループすることで簡単に回復でき、2つのビット文字列を連結するだけで、位置yで見つかった各zを(直接またはそこで参照されるチェーン内で)元のzに再構成します値x = 2 m y + z。f(S)Azyx=2my+z

分布が均一に近く、がNを超えると、チェーニングがあまりなく(これは通常の方法で評価できます)、チェインは短くなる傾向があります。分布が不均一な場合でも、アルゴリズムは機能しますが、2次のタイミングに達する可能性があります。それが可能である場合は、チェーンよりも効率的なものを使用してください(そしてストレージに少しのオーバーヘッドを払ってください)。2kN

必要なストレージが最大であるに対するビットAと2 2 k個のチェーンのビット(仮定M ≤ kは)。これは、それぞれnビットの2 k値を格納するために必要なスペースです。均一性に自信がある場合は、チェーン用のストレージを十分に割り当てることができません。不均一性が発生する可能性がある場合は、kを増やして、チェーンストレージを完全に推奨することができます。2nA22km≤k2knk

このソリューションに関する別の考え方は、これが特に優れたハッシュ関数(最上位ビットを取る)を持つハッシュテーブルであり、そのため、最下位m = n − kビットのみを格納する必要があることです。テーブル。km=n−k

チェーンのストレージをのストレージでオーバーレイする方法はいくつかありますが、それほどスペースを節約せず(mがkよりもはるかに小さいと想定)、コードの開発が難しくなるため、それは煩わしいものではありません。デバッグし、維持します。Amk


1
私は、最後から2番目の段落がここの中心的な段落であり、おそらく(アイデアとして)一番上にあるはずだと思います。「bin and chain」という用語はわかりません(ただし、投稿を読んだ後で意味がわかります)。このアイデアは、試行に拡張できます。
— ラファエル

したがって、これは分散が不十分な入力のです。これがどのように効率的かわかりません。Θ(n2)
— einpoklum 2018年

@einpoklumこの回答は、ソリューションが効率的である条件を明確に説明しています。
— whuber 2018
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.