C++で配列内の各要素より大きい直近の値を効率的に検索する方法
この記事では、配列内のすべての要素について、それより大きい値の中で最も近いもの(次に大きい要素)を検索する方法を解説します。要素 x より大きい値が配列内に存在する場合はその値を出力し、存在しない場合は -1 を返します。
例として、配列が [10, 5, 11, 6, 20, 12] の場合を考えてみましょう。このとき、各要素に対する次に大きい値は [11, 6, 12, 10, -1, 20] となります。最大値である 20 より大きい要素は配列内に存在しないため、-1 を出力します。
解決のアプローチ
この問題を解くには、C++ STL の set(セット)を利用します。set は二分探索木(バランス木)をベースに実装されており、常に要素がソートされた状態で保持されます。二分探索木では中順走査(in-order traversal)における後続ノードが「次に大きい要素」に相当するため、upper_bound() 関数を使えば O(log n) の計算量で目的の要素を取得できます。
アルゴリズムの手順
- 配列のすべての要素を set に挿入します。
- 各要素に対して
upper_bound(arr[i])を呼び出し、その要素より大きい最小の要素を取得します。 - イテレータが
end()を指す場合(より大きい要素が存在しない場合)は -1 を出力し、それ以外はイテレータが指す値を出力します。
C++での実装例
#include<iostream>
#include<set>
using namespace std;
void nearestGreatest(int arr[], int n) {
set<int> tempSet;
// すべての要素をsetに挿入
for (int i = 0; i < n; i++)
tempSet.insert(arr[i]);
// 各要素より大きい直近の値を検索して出力
for (int i = 0; i < n; i++) {
auto next_greater = tempSet.upper_bound(arr[i]);
if (next_greater == tempSet.end())
cout << -1 << " ";
else
cout << *next_greater << " ";
}
}
int main() {
int arr[] = {10, 5, 11, 6, 20, 12};
int n = sizeof(arr) / sizeof(arr[0]);
nearestGreatest(arr, n);
}実行結果
11 6 12 10 -1 20
計算量について
このアルゴリズムの時間計算量は、set への挿入と upper_bound の検索がそれぞれ O(log n) であり、これを n 個の要素に対して行うため、全体で O(n log n) となります。単純な全要素比較による O(n²) のアプローチと比べて大幅に高速化できる点が大きなメリットです。また、空間計算量は set の分だけ余分に必要となるため O(n) です。
-
C++で配列内の各要素に最も近い大きい値を効率的に検索する方法
この記事では、配列内の各要素に対して「最も近い大きい値」を効率的に検索する方法を解説します。ある要素 x より大きい値が配列内に存在する場合、その中で最も小さい値(次に大きい要素)をその要素の答えとし、存在しない場合は -1 を出力します。例として、配列が {10, 5, 11, 10, 20, 12} の場合、結果は {11, 10, 12, 11, -1, 20} となります。最大値の 20 より大きい要素は配列内に存在しないため、20 に対しては -1 が出力されます。解決のアプローチこの問題は C++ STL の set(セット)を使うと簡単に解決できます。set は二分探索木をベース
-
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重のループを使用し、外側のループで各要素を順に取り上