C++で入力と同じ順序で「次に大きい要素」を出力する方法
「次に大きい要素(Next Greater Element)」とは、ある要素の後ろに位置する要素の中で、その要素より初めて大きくなる要素のことです。具体例を見てみましょう。
arr = [4, 5, 3, 2, 1]
この場合、4に対する次に大きい要素は5です。一方、3、2、1の後ろにはそれらより大きい要素が存在しないため、-1が対応します。
アルゴリズム
配列をランダムな数値で初期化します。
スタックと結果格納用の配列を初期化します。
配列の末尾から先頭に向かって走査します。
スタックが空になるか、スタックの先頭要素が現在の要素以下になるまで、要素を取り除きます(pop)。
スタックが空になった場合は、次に大きい要素が存在しないため、結果配列に-1を追加します。
スタックが空でない場合は、スタックの先頭要素が現在の要素に対する「次に大きい要素」となるため、それを結果配列に追加します。
現在の要素をスタックにプッシュします。
結果配列を走査し、各要素とその次に大きい要素を入力と同じ順序で出力します。
実装
以下は、上記のアルゴリズムをC++で実装した例です。
#include <bits/stdc++.h>
using namespace std;
void nextGreaterElements(int arr[], int n) {
stack<int> s;
int result[n];
for (int i = n - 1; i >= 0; i--) {
while (!s.empty() && s.top() <= arr[i]) {
s.pop();
}
if (s.empty()) {
result[i] = -1;
} else {
result[i] = s.top();
}
s.push(arr[i]);
}
for (int i = 0; i < n; i++) {
cout << arr[i] << " -> " << result[i] << endl;
}
}
int main() {
int arr[] = { 1, 2, 3, 4, 5 };
int n = 5;
nextGreaterElements(arr, n);
return 0;
}出力
上記のコードを実行すると、以下の結果が得られます。
1 -> 2 2 -> 3 3 -> 4 4 -> 5 5 -> -1
計算量
このアルゴリズムの時間計算量はO(n)です。各要素はスタックに最大1回プッシュされ、最大1回ポップされるため、処理は配列の長さに対して線形に完了します。空間計算量についても、結果配列とスタックの分だけO(n)のメモリを使用します。単純な二重ループによるO(n²)の素朴な手法と比べ、大きな入力に対しても効率的に動作する点がこのアプローチの大きな利点です。
-
C++で同じ順序ですべての要素を含む最小の部分配列を見つける方法
サイズ m と n の2つの配列があるとします。このとき、1つ目の配列の中から、2つ目の配列のすべての要素を含む最小長の部分配列(サブ配列)を見つけるのが課題です。重要なポイントとして、2つ目の配列の要素は1つ目の配列内で連続していなくても構いませんが、出現する順序は同じでなければなりません。具体例例えば、次のような2つの配列を考えてみましょう。A = [2, 2, 4, 5, 8, 9]B = [2, 5, 9]この場合、出力は 5 になります。なぜなら、A の中で条件を満たす最小の部分配列は [2, 4, 5, 8, 9] であり、B の要素 [2, 5, 9] がすべて同じ順序で含まれて
-
C++で配列内の各要素に最も近い大きい値を効率的に検索する方法
この記事では、配列内の各要素に対して「最も近い大きい値」を効率的に検索する方法を解説します。ある要素 x より大きい値が配列内に存在する場合、その中で最も小さい値(次に大きい要素)をその要素の答えとし、存在しない場合は -1 を出力します。例として、配列が {10, 5, 11, 10, 20, 12} の場合、結果は {11, 10, 12, 11, -1, 20} となります。最大値の 20 より大きい要素は配列内に存在しないため、20 に対しては -1 が出力されます。解決のアプローチこの問題は C++ STL の set(セット)を使うと簡単に解決できます。set は二分探索木をベース