C++で回転ソート済み配列の回転回数を求める方法
ここでは、回転ソート済み配列(Rotated Sorted Array)が与えられたときに、その配列を元のソートされた状態に戻すために必要な回転回数を求める問題を扱います。なお、回転は「右から左へ」要素を移動させる操作として考えます。
例えば、次のような配列を考えてみましょう。
{15, 17, 1, 2, 6, 11}この配列をソートするには、2回の回転が必要です。回転を繰り返すと、最終的に次の順序になります。
{1, 2, 6, 11, 15, 17}この場合の出力(回転回数)は 2 となります。
解法のポイント
この問題のロジックは非常にシンプルです。配列を注意深く観察すると、必要な回転回数は「最小要素のインデックス」と一致することがわかります。
つまり、配列内の最小要素を見つけられれば、そのインデックスがそのまま答えになります。これは、回転ソート済み配列では最小要素が「回転の境界位置」に必ず存在するためです。
アルゴリズムの手順
- 配列の先頭要素を仮の最小値としてインデックス0を記録します。
- 配列を先頭から順に走査し、より小さい要素が見つかるたびにそのインデックスを更新します。
- 走査が終わった時点で記録されているインデックスが、回転回数(=最小要素の位置)となります。
C++での実装例
#include <iostream>
using namespace std;
// 最小要素のインデックスを返す関数
int getMinIndex(int arr[], int n){
int index = 0;
for(int i = 1; i < n; i++){
if(arr[i] < arr[index]){
index = i;
}
}
return index;
}
// 必要な回転回数を求める関数
int countNumberOfRotations(int arr[], int n){
return getMinIndex(arr, n);
}
int main() {
int arr[] = {15, 17, 1, 2, 6, 11};
int n = sizeof(arr)/sizeof(arr[0]);
cout << "Number of required rotations: " << countNumberOfRotations(arr, n);
}実行結果
Number of required rotations: 2
計算量について
上記の線形探索によるアプローチの計算量は O(n) です。配列のすべての要素を一度確認するため、シンプルで確実な方法と言えます。
なお、配列が「ソート済み配列を回転させたもの」であるという性質を利用すると、二分探索(Binary Search)を使って O(log n) の計算量で最小要素の位置を見つけることも可能です。大規模な配列を扱う場合は、こちらの手法を検討するとより効率的です。
-
C++で配列内の数値の頻度(出現回数)を求める方法
配列に n 個の異なる要素が格納されているとします。この配列の中から、特定の要素が何回出現するか(頻度)を調べたい場合があります。例えば、配列 A = [5, 12, 26, 5, 3, 4, 15, 5, 8, 4] の中で「5」の頻度を調べると、答えは 3 になります。アルゴリズムの考え方この問題は、次の手順で解くことができます。1. 配列を左端から順に走査します。2. 現在の要素が調べたい数値と一致したら、カウンターを1つ増やします。3. 一致しない場合は、そのまま次の要素へ進みます。4. 配列の最後まで走査したら、カウンターの値が頻度となります。このアルゴリズムの計算量は O(n) で
-
C++で配列内の各要素のサーパッサー(Surpasser)の数を求めるアルゴリズム
ある配列Aが与えられたとき、各要素の「サーパッサー(surpasser)」の数を求める問題を考えてみましょう。サーパッサーとは、現在注目している要素よりも右側に存在する、その要素より大きい値のことです。 例えば、A = {2, 7, 5, 3, 0, 8, 1} という配列の場合、サーパッサーの数は {4, 1, 1, 1, 2, 0, 0} となります。これは、先頭の「2」の右側には「7・5・3・8」という4つの大きな値が存在するためです。その他の要素についても同じルールで数えていきます。 アルゴリズムの考え方 解法は非常にシンプルです。2重のループを使用し、外側のループで各要素を順に取り上