各名前を128要素のビット文字列と見なします。 各エントリには、b [i]とc [i]という2つの行があります。
まず、各iについて、すべてのエントリの差b [i] -c [i]の合計s [i]を見つけた場合にどうなるかを見てみましょう。
名と姓を除くすべての名前が行bとcに同じ回数出現するため、合計すると名前が破棄され、名と姓のビットの差が合計に残ります。 したがって、s [i]の値は、-1、0、または1の値を取ることができます。
s [i] =-1の場合、名のb [i]の値は0、2番目の名前の値は1です。s[i] = 1の場合、値はそれぞれ1と0になります。 ただし、s [i] = 0の場合、姓と名のこのビットの値は同じであるとしか言えません。 どうやって見つけますか?
あるkについて、s [k]がゼロでないことがわかっていると仮定します。 XOR値(b [i]&b [k])^(c [i]&c [k])を見つけたらどうなりますか?
最初と最後を除くすべての名前nについて、式n [i]&n [k]は合計に2回(1回はb、2回目はc)含まれ、ゼロの寄与を与えます。 fが名で、pが最後の場合、合計は(f [i]&f [k])^(p [i]&p [k])になります。 f [i] = p [i]であるビットのみに関心があります(残りの値は既に見つかっています)。 したがって、(f [i]&f [k])^(p [i]&p [k])= f [i]&(f [k] ^ p [k])、およびs [k]!= 0以降、次にf [k] ^ p [k] = 1で、合計量はf [i]です。
残念ながら、どのビットが名前が異なるかを事前に言うことはできません。 したがって、念のため、合計を検討します
(b [i]&b [k])^(c [i]&c [k])すべてのペアi、k。 合計で、128 * 127/2 = 8128の1ビットカウンターと128の2ビットカウンターが必要です(s [i]をカウントするため)。
たとえば、次のような処理を記述できます(レコード内の両方の名前が同じバイト配列で送信され、行に書き込まれると仮定します)。
static byte[] FindDiffNames(IEnumerable<byte[]> seq) { const int LName=16; byte[,] pairs=new byte[LName*8,LName]; byte[] res=new byte[2*LName]; foreach(byte[] name in seq) { for(int i=0;i<LName;i++) { res[i+LName]^=(byte)(name[i]&res[i]); res[i]^=(byte)(name[i]^name[i+LName]); res[i+LName]^=(byte)(name[i+LName]&res[i]); for(int k=0;k<LName*8;k++) { byte mask=(byte)(1<<(k&7)); if((name[k>>3]&mask)!=0) pairs[k,i]^=name[i]; if((name[LName+(k>>3)]&mask)!=0) pairs[k,i]^=name[i+LName]; } } } for(int i=0;i<LName;i++) { int b0=res[i],b1=res[i+LName],s=0; for(int j=0;j<LName*8;j++) s|=pairs[j,i]; s&=~b0; res[i]=(byte)((b0&~b1)|s); res[i+LName]=(byte)((b0&b1)|s); } return res; }
この手法を使用すると、2つまたは3つの要素を追加する(または2つを追加してから1つを削除する)ことによって取得されるセットの差を見つけることもできます。 差がより強い場合、ペアだけでなくビットのトリプルの接続詞の合計を保存する必要があります。 XORはすでに十分ではありません-少なくとも3ビットの交互合計を数える必要があります。
UPD:コメントでのこのタスクの議論で、
セプティムはよりシンプルなソリューションを提案しました。 名前を128ビット整数(xi、yi)と見なし、合計S1 =合計(xi-yi)、S2 =合計(xi ^ 2-yi ^ 2)(最初の合計は符号付き129ビット、2番目は-符号付き257ビット。オーバーフローを無視し、それぞれ2 ^ 129と2 ^ 257を法として動作します)。 それらの値がS1 = x1-xn、S2 = x1 ^ 2-xn ^ 2であることは明らかです。x1は名、xnは最後です。 これから、x1 =(S1 + S2 / S1)/ 2、xn = x1-S1を簡単に見つけることができます。