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

C++で二分探索を使ってソート済み配列内の一意の要素を見つける方法

ソート済み配列から一度だけ現れる要素を検索する

ソート済みの配列Aがあるとします。すべての要素は2回ずつ現れますが、1つの要素だけが1回しか現れません。この一意の要素を見つける必要があります。例えば、配列が [1, 1, 3, 3, 4, 4, 5, 6, 6, 7, 7, 9, 9] の場合、求める要素は5です。

この問題は、二分探索(バイナリサーチ)のアプローチを用いて効率的に解決できます。一意の要素より前の部分では、各要素の最初の出現位置が偶数インデックス(0, 2, 4, ...)に、2回目の出現位置が奇数インデックス(1, 3, 5, ...)にあります。しかし、一意の要素より後ろではこのパターンが逆転し、最初の出現が奇数インデックスに、2回目の出現が偶数インデックスに現れます。

この性質を利用して、まず中央インデックスmidを求めます。midが偶数の場合はA[mid]とA[mid+1]を比較し、両者が同じであれば一意の要素は右側に存在するため探索範囲を右へ移動し、異なれば左側へ移動します。midが奇数の場合はA[mid]とA[mid-1]を比較し、同じであれば右側へ、異なれば左側へ探索範囲を狭めていきます。この処理を繰り返すことで、O(log n)の時間計算量で一意の要素を特定できます。

実装例

#include<iostream>
using namespace std;
void findSingleElement(int *arr, int left, int right) {
   if (left > right)
      return;
   if (left==right) {
      cout << "The required element is: "<< arr[left];
      return;
   }
   int mid = (left + right) / 2;
   if (mid%2 == 0) {
      if (arr[mid] == arr[mid+1])
         findSingleElement(arr, mid+2, right);
      else
         findSingleElement(arr, left, mid);
   }else{
      if (arr[mid] == arr[mid-1])
         findSingleElement(arr, mid+1, right);
      else
         findSingleElement(arr, left, mid-1);
   }
}
int main() {
   int arr[] = {1, 1, 3, 3, 4, 4, 5, 6, 6, 7, 7, 9, 9};
   int len = sizeof(arr)/sizeof(arr[0]);
   findSingleElement(arr, 0, len-1);
}

出力

The required element is: 5

計算量の分析

このアルゴリズムの時間計算量はO(log n)です。各ステップで探索範囲が半分に縮小されるため、線形走査によるO(n)のアプローチと比較して大幅に効率的です。空間計算量については、再帰呼び出しのスタックを除けばO(1)となります。なお、再帰をループに書き換えることで、空間計算量をO(1)に抑えることも可能です。

  1. C++でN階乗の合計の下2桁を求める方法

    本記事では、1!からN!までの階乗の合計について、その下2桁(一の位と十の位)を求める方法を解説します。例えば N = 4 の場合、1! + 2! + 3! + 4! = 33 となるため、一の位は「3」、十の位は「3」であり、結果は「33」となります。この問題には重要な性質があります。N が 5 より大きい場合、その階乗の一の位は必ず 0 になるため、6! 以降の項は一の位に一切影響を与えません。同様に、N が 10 以上になると十の位も 0 のまま変化しなくなります。したがって、N = 10 以上では結果は常に「13」で固定されます。実際に N = 1 から 10 までの階乗の値を表に整理

  2. C++で配列の最大要素とその位置を見つける方法

    配列の最大要素とは配列には複数の要素が格納されており、その中で他のすべての要素よりも大きい値を持つものが「最大要素」です。具体例51724上記の配列の場合、最大要素は7であり、インデックス2の位置に存在します。それでは、配列の最大要素を求めるC++プログラムを見ていきましょう。サンプルコード#include <iostream> using namespace std; int main() { int a[] = {4, 9, 1, 3, 8}; int largest, i, pos; largest = a[0]; for(i=1; i<