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

C++でビット配列を活用して配列内の重複要素を検出する方法

概要

n個の数値からなる配列が与えられます(nは最大32,000)。この配列には重複した要素が含まれている可能性がありますが、nの値は事前には分かりません。ここでの課題は、利用可能なメモリがわずか4キロバイトという厳しい制約のもとで、配列内のすべての重複要素をどのように検出・表示するかというものです。

入力例

arr[] = {2, 6, 2, 11, 13, 11}

出力例

2 11
2と11は、与えられた配列内で複数回出現しています。

入力例

arr[] = {60, 50, 60}

出力例

60

アプローチ

4キロバイトのメモリがあるということは、最大で 8 × 4 × 210 ビット(約327,680ビット)まで扱えることを意味します。32 × 210 ビットは32,000よりも大きいため、各ビットが1つの整数に対応する32,000ビットのビットベクタを作成することができます。

また、32,000ビットを超えるビットベクタが必要になった場合でも、同様の方法で簡単に拡張できる点にも注目してください。このビットベクタを用いることで、配列を順番に走査しながら、各要素 v に対して「ビット v を1にセット」してフラグを立てていきます。そして、走査中にすでにフラグが立っている要素(= 重複要素)に遭遇したら、その値を出力します。

仕組みのポイント

  • 右シフト演算(pos >> 5):32で割ることと同じ意味であり、対象のビットが格納されている整数のインデックスを求めます。
  • ビットマスク(pos & 0x1F):31(0x1F)との論理積を取ることで、その整数内におけるビット番号(0〜31)を特定します。
  • 計算量:時間計算量は O(n)、必要な追加メモリは約4KB(32,000ビット ≒ 4,000バイト)に抑えられます。

C++による実装例

// 配列内のすべての重複を出力するC++プログラム
#include <bits/stdc++.h>
using namespace std;

// 整数の配列を用いてビット配列を表現するクラス
class BitArray{
   int *arr1;
   public:
   BitArray() {}
   // コンストラクタ
   BitArray(int n1){
      // 32で割る処理。nビットを格納するには
      // n/32 + 1 個の整数が必要(intが32ビットの場合)
      arr1 = new int[(n1 >> 5) + 1];
   }
   // 指定位置のビット値を取得
   bool get(int pos1){
      // 32で割り、対応する整数の位置を求める
      int index1 = (pos1 >> 5);
      // arr[index] 内のビット番号を求める
      int bitNo1 = (pos1 & 0x1F);
      // 指定されたビットの値を判定して返す
      return (arr1[index1] & (1 << bitNo1)) != 0;
   }
   // 指定位置のビットをセット
   void set(int pos1){
      // ビット位置のインデックスを求める
      int index1 = (pos1 >> 5);
      // arr1[index1] 内の該当ビットをセット
      int bitNo1 = (pos1 & 0x1F);
      arr1[index1] |= (1 << bitNo1);
   }
   // すべての重複を出力するメイン関数
   void checkDuplicates1(int arr1[], int n1){
      // 32000ビットのビット配列を作成
      BitArray ba1 = BitArray(320000);
      // 配列要素を順に走査
      for (int i = 0; i < n1; i++){
         // ビット配列上のインデックスに相当する値
         int num1 = arr1[i];
         // numがすでにビット配列に存在する場合(重複)
         if (ba1.get(num1))
            cout << num1 << " ";
         // 存在しない場合はビットをセットして登録
         else
            ba1.set(num1);
      }
   }
};
// ドライバーコード
int main(){
   int arr1[] = {2, 6, 2, 11, 13, 11};
   int n1 = sizeof(arr1) / sizeof(arr1[0]);
   BitArray obj1 = BitArray();
   obj1.checkDuplicates1(arr1, n1);
   return 0;
}

実行結果

2 11

  1. C++でSTLを使って配列の積を求める方法

    C++では、STL(標準テンプレートライブラリ)のaccumulate関数を利用することで、配列内のすべての要素の積を簡潔に求めることができます。ここでは、その具体的な実装例を紹介します。 アルゴリズム 開始 配列の各要素の値を初期化する。 ユーザー定義関数 accumulate を呼び出し、配列全体の積を取得する。 計算結果を出力する。 終了 サンプルコード #include <iostream> #include <numeric> using namespace std; int ProductOfArray(int p[], int n)

  2. Pythonでビット配列を使って配列内の重複を検出する方法

    n個の数値からなる配列があるとします。nは最大でも32,000であり、配列には重複した要素が含まれている可能性がありますが、nの具体的な値は分かりません。ここで、使用できるメモリがわずか4キロバイトしかないという制約のもと、配列内のすべての重複をどのように表示すればよいでしょうか?例えば、入力が [2, 6, 2, 11, 13, 11] の場合、2と11がそれぞれ複数回出現しているため、出力は [2, 11] となります。なぜビット配列なのか通常、重複検出にはハッシュセットなどを使用しますが、32,000個の整数をそのまま格納すると必要なメモリが制限を超えてしまいます。そこで各数値を「1ビッ