Pythonでビット単位のANDを使ってすべてのペアのXOR合計を効率的に求めるプログラム
問題の概要
2つの配列 arr1 と arr2 が与えられているとします。ここで「リストのXOR合計」とは、リスト内の全要素をビット単位XOR(排他的論理和)で結合した値のことを指します。リストに要素が1つしかない場合、そのXOR合計はその要素自体になります。
次に、0 <= i < len(arr1) および 0 <= j < len(arr2) を満たすすべてのインデックスペア (i, j) について、arr1[i] AND arr2[j](ビット単位AND)の結果を要素として持つリストを考えます。この記事では、そのリスト全体のXOR合計を求める方法を解説します。
具体例
たとえば、入力が arr1 = [5, 3, 4]、arr2 = [2, 6] の場合を考えてみましょう。
まず、すべてのペアのANDを計算すると、次のリストが得られます。
[5 AND 2, 5 AND 6, 3 AND 2, 3 AND 6, 4 AND 2, 4 AND 6]
= [0, 4, 2, 2, 0, 4]
このリストのXOR合計は以下のようになります。
0 XOR 4 XOR 2 XOR 2 XOR 0 XOR 4 = 0
したがって、出力は 0 となります。
解法のアプローチ
すべてのペアを二重ループで総当たり的に計算することも可能ですが、より効率的な方法があります。手順は以下の通りです。
xor1 := 0、xor2 := 0と初期化します。arr1の各要素aに対して、xor1 := xor1 XOR aを実行します。arr2の各要素aに対して、xor2 := xor2 XOR aを実行します。- 最後に
xor1 AND xor2を返します。
なぜこの方法で正しく求まるのか
ポイントは、AND演算がXORに対して分配法則を満たすという性質です。つまり、任意の整数 x, y, z について次の等式が成り立ちます。
(x XOR y) AND z = (x AND z) XOR (y AND z)
この性質を繰り返し適用すると、「すべてのペア (arr1[i] AND arr2[j]) のXOR」は「arr1 の全要素のXOR」と「arr2 の全要素のXOR」のANDに等しいことが分かります。そのため、O(n×m) の二重ループを回す代わりに、O(n + m) の計算量で答えを求めることができ、配列が大きい場合でも高速に処理できます。
Pythonでの実装例
それでは、上記のアルゴリズムをPythonで実装してみましょう。
def solve(arr1, arr2):
xor1 = 0
xor2 = 0
for a in arr1:
xor1 ^= a
for a in arr2:
xor2 ^= a
return xor1 & xor2
arr1 = [5, 3, 4]
arr2 = [2, 6]
print(solve(arr1, arr2))
入力
[5, 3, 4], [2, 6]
出力
0
まとめ
この問題は、AND演算の分配法則を活用することで、各ペアを個別に計算せずに済むのが大きな特徴です。各配列のXOR合計を先に求めてからANDを取るだけでよいため、計算量は O(n + m) に抑えられます。ビット演算の数学的な性質を理解していれば、シンプルで効率的なコードが書ける好例といえるでしょう。
-
Pythonで配列(リスト)の合計を求める方法をわかりやすく解説
この記事では、配列(リスト)の合計値を求めるという問題に対して、Pythonでの解決策とアプローチをわかりやすく解説します。 問題の定義 配列が入力として与えられたとき、その配列に含まれるすべての要素の合計を計算することを目標とします。 例えば、[1, 2, 3, 4, 5] という配列が与えられた場合、出力は 15 になります。 アプローチ1:ループを使った素朴な方法(総当たり法) 最も基本的な方法は、リストを先頭から順に走査し、各要素を合計用の変数に加算していくやり方です。手順は以下の通りです。 合計を格納する変数を 0 で初期化します。 for ループでリストの各要素を取り出し、順番に
-
Pythonでリスト内のすべてのペア間の絶対差の合計を求めるプログラム
本記事では、リスト内のすべてのペア間の絶対差の合計を求める問題の解法とアプローチについて解説します。 問題文 リストが入力として与えられたとき、そのリスト内のすべてのペア間の絶対差の合計を求める必要があります。 解法のアプローチ enumerate() メソッドは、イテラブル(反復可能オブジェクト)にカウンターを付加し、enumerate オブジェクトとして返す組み込み関数です。ループ処理の中でインデックスと要素を同時に取得したい場合に非常に便利です。 この手法では、まず絶対差を格納するためのリスト「diffs」を用意します。 次に、2つの変数を持つ二重ループを使用します。片方はカウンター(イ