C++
 Computer >> コンピューター >  >> プログラミング >> C++

C++でサイズkの部分配列における最大XOR値を効率的に求める方法

この問題では、n個の要素からなる配列 arr[] と整数 k が与えられます。求めるのは、サイズkの部分配列(サブアレイ)の中で、要素全体のXOR値が最大になるものです。

入力例

arr[] = {3, 1, 6, 2, 7, 9}
k = 3

出力例

12

説明

サイズkのすべての部分配列と、その要素のXOR値は以下のようになります。

{3, 1, 6} = 4
{1, 6, 2} = 5
{6, 2, 7} = 3
{2, 7, 9} = 12

この中で最大のXOR値は 12 であり、これが答えとなります。

解法アプローチ

シンプルな解法:二重ループ

最も単純な方法は、二重ループを使うことです。外側のループで配列を走査し、内側のループで各部分配列の全要素のXORを計算します。そして、得られたXOR値のうち最大のものを返します。

この方法でも正しい結果は得られますが、計算量はO(n×k)となり、配列が大きい場合は非効率です。そこで、より優れたアプローチを紹介します。

効率的な解法:スライディングウィンドウ

XORには x ^ a ^ x = a という重要な性質があります。同じ値を2回XORすると元に戻るという性質で、これを利用すると「要素の削除」が可能になります。

まず、インデックス0から始まるサイズkの部分配列のXOR値を計算します。次に、配列を先頭から順に走査しながら、以下の操作を繰り返します。

  1. 現在のXOR値に対して XOR ^ arr[i - k] を実行し、ウィンドウの先頭の要素を取り除きます。これにより、直前のインデックス+1から現在のインデックス-1までの部分配列のXOR値が得られます。
  2. 続いて XOR ^ arr[i] を実行し、新しい要素をウィンドウに追加して、現在の部分配列のXOR値を更新します。

この操作を毎回行いながら、すべてのXOR値の中から最大値を見つけて返します。この方法なら計算量はO(n)に抑えられ、非常に効率的です。

ソリューションの実装例

#include<iostream>
using namespace std;

int findMaxSubArrayXOR(int arr[], int n, int k) {
    int currentXORVal = 0;
    // 最初のk個の要素のXORを計算
    for (int i = 0; i < k; i++)
        currentXORVal = currentXORVal ^ arr[i];
    int maxXor = currentXORVal;
    // スライディングウィンドウで残りの部分配列を処理
    for (int i = k; i < n; i++) {
        currentXORVal = currentXORVal ^ arr[i - k]; // 先頭の要素を除去
        currentXORVal = currentXORVal ^ arr[i];     // 新しい要素を追加
        maxXor = max(maxXor, currentXORVal);
    }
    return maxXor;
}

int main() {
    int arr[] = {3, 1, 6, 2, 7, 9};
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 3;
    cout << "サイズ " << k << " の部分配列の最大XOR値は "
         << findMaxSubArrayXOR(arr, n, k);
    return 0;
}

出力

サイズ 3 の部分配列の最大XOR値は 12

まとめ

XORの性質「x ^ a ^ x = a」を活用したスライディングウィンドウ手法を使うことで、サイズkの部分配列の最大XOR値をO(n)の時間計算量で効率的に求めることができます。二重ループによるO(n×k)の素朴な解法と比べ、大規模な配列に対しても高速に動作するのが大きな利点です。

  1. C++で指定された値に最も近いk個の要素を検索する方法

    いくつかの要素を含む配列 A があるとします。ここに、値 X と整数 k も与えられます。この課題は、配列 A の中から X に最も近い k 個の要素を見つけることです。なお、X が配列内に存在する場合は、その要素自体は出力に含めません。 例として、A = [12, 16, 22, 30, 35, 39, 42, 45, 48, 50, 53, 55, 56]、X = 35、k = 4 とすると、出力は「30, 39, 42, 45」になります。 解法の考え方:二分探索を活用する この問題を効率的に解くには、二分探索(バイナリサーチ)の手法を利用します。二分探索によって「クロスオーバーポイ

  2. C++で配列内の最小値の出現回数(頻度)を求める方法

    この記事では、配列の中で最小の要素が何回出現するか(頻度)を求める方法を解説します。例として、配列の要素が [5, 3, 6, 9, 3, 7, 5, 8, 3, 12, 3, 10] である場合を考えてみましょう。この配列の最小値は 3 であり、その出現回数は 4 回です。したがって、出力は 4 となります。解決のアプローチこの問題を解く手順は非常にシンプルで、以下の2ステップで構成されます。1. まず、配列全体を走査して最小値を見つける2. 次に、その最小値と一致する要素の個数を数えるこの方法の時間計算量は O(n) であり、配列を2回走査しますが、線形時間で処理が完了するため効率的です。