ビット配列[〜#〜] and [〜#〜]が2
の累乗である配列内の順序付けられていないペアの数を計算する方法。 exの場合、配列が[10,7,2,8,3]
です。答えは6
です。説明(0ベースのインデックス):
a[0]&a[1] = 2
a[0]&a[2] = 2
a[0]&a[3] = 8
a[0]&a[4] = 2
a[1]&a[2] = 2
a[2]&a[4] = 2
私の頭に浮かぶ唯一のアプローチはブルートフォースです。 O(n)またはO(n * log(n))で実行するように最適化する方法は?
配列のサイズの制約は、最大10^5
にすることができます。そして、その配列の値は10^12
までです。
これが私が試したブルートフォースコードです。
int ans = 0;
for (int i = 0; i < a.length; i++) {
for (int j = i + 1; j < a.length; j++) {
long and = a[i] & a[j];
if ((and & (and - 1)) == 0 && and != 0)
ans++;
}
}
System.out.println(ans);
値の配列をインデックスセットの配列に変換します。各セットは特定のビットに対応し、ビットセットを持つ元のセットの値のインデックスを含みます。たとえば、サンプルの配列A = [10,7,2,8,3]
はB = [{1,4}, {0,1,2,4}, {1}, {0,3}]
になります。固定サイズのビットベクトルの配列は、集合和集合/交差/集合マイナスを比較的簡単かつ効率的にするため、このための理想的なデータ構造です。
セットBの配列を取得したら(O(nm) time where m
is integers of your integers of bits))、すべての要素に対して繰り返しますi Aの再計算、∑の計算j| Bj∖i∖⋃kBk:k≠j∧i∈Bk|:i∈Bj。それらをすべて追加して2で除算し、そのshouldはペアの数になります(「2で除算」は、これが各ペアを2回カウントするためです。番号のペア)。 O(nm2)セットマイナス操作をO(1)として数えると仮定すると、それらをO(n)として数えると、O(n2)、ただし、効率的なビットセットがある場合、少なくとも定数係数は小さくする必要があります。
疑似コード:
foreach A[i] in A:
foreach bit in A[i]:
B[bit] += {i}
pairs = 0
foreach A[i] in A:
foreach B[j] in B:
if i in B[j]:
tmp = B[j] - {i}
foreach B[k] in B:
if k != j && i in B[k]:
tmp -= B[k]
pairs += |tmp|
return pairs/2