C++で配列内のサブ配列平均値の平均を求めるアルゴリズム
問題の概要
この記事では、サイズnの整数型配列arr[]と整数mが与えられたときに、サブ配列平均の平均を求める方法を解説します。ここでいうサブ配列とは、元の配列から連続するm個の要素を取り出したものを指します。
つまり、まず各サブ配列の平均値を計算し、次にそれらの平均値をさらに平均した値を求めることになります。
入力例と出力例
入力
arr[] = {2, 5, 3, 6, 1}, m = 3出力
3.78
計算の流れ
サイズm=3のサブ配列は {2, 5, 3}、{5, 3, 6}、{3, 6, 1} の3つ存在します。それぞれの平均は以下のように計算できます。
- {2, 5, 3} の平均:(2+5+3)/3 = 10/3
- {5, 3, 6} の平均:(5+3+6)/3 = 14/3
- {3, 6, 1} の平均:(3+6+1)/3 = 10/3
これらの平均値の平均は、
(10/3 + 14/3 + 10/3) ÷ 3 = (34/3) ÷ 3 = 34/9 ≈ 3.78
解法アプローチ
アプローチ1:すべてのサブ配列を調べるシンプルな解法
最も直感的な方法は、サイズmのサブ配列をすべて列挙してそれぞれの平均を求め、その合計をサブ配列の個数で割るというものです。実装は簡単ですが、各サブ配列の合計を毎回計算し直すため、時間計算量はO(n×m)となり、配列が大きい場合には非効率になります。
アプローチ2:スライディングウィンドウ法(効率的な解法)
計算量を抑えたい場合は、スライディングウィンドウ(尺取り法)を使うのが効果的です。
まずインデックス0から始まるサイズmのウィンドウの合計を求めます。その後、ウィンドウを1つずつ右へずらすたびに、「左端の要素を引き、新しく入ってくる右端の要素を足す」という操作だけで合計を更新できるため、各ステップの更新コストはO(1)で済みます。
各ウィンドウの平均を順に加算していき、最後にウィンドウの個数(n − m + 1)で割れば、求める答えが得られます。
- 時間計算量:O(n)
- 空間計算量:O(1)
C++での実装例
以下は、スライディングウィンドウ法を用いてこの問題を解くC++プログラムです。
#include <iostream>
using namespace std;
// サブ配列平均の平均を計算する関数
float calcMeanOfSubarrayMeans(int arr[], int n, int m) {
float meanSum = 0, windowSum = 0;
// 最初のウィンドウ(サイズm)の合計を求める
for (int i = 0; i < m; i++)
windowSum += arr[i];
meanSum += windowSum / m;
// ウィンドウを1つずつスライドさせながら平均を加算
for (int i = m; i < n; i++) {
windowSum = windowSum - arr[i - m] + arr[i];
meanSum += windowSum / m;
}
// ウィンドウ(サブ配列)の個数で割って結果を返す
int windowCount = n - m + 1;
return meanSum / windowCount;
}
int main() {
int arr[] = { 2, 5, 3, 6, 1 };
int n = sizeof(arr) / sizeof(arr[0]);
int m = 3;
cout << "サブ配列平均の平均は " << calcMeanOfSubarrayMeans(arr, n, m) << endl;
return 0;
}実行結果
サブ配列平均の平均は 3.77778
まとめ
サブ配列平均の平均を求める問題は、スライディングウィンドウを活用することでO(n)の時間計算量で効率的に解くことができます。「ウィンドウの合計を再利用する」というテクニックは、部分和や移動平均など、さまざまな配列操作の問題に応用できるので、ぜひ覚えておきましょう。
-
C++で行列の平均ベクトルを求める方法をわかりやすく解説
M × N の行列が与えられたとき、その平均ベクトルを求めることを考えます。例えば、次のような 3 × 3 の行列があるとします。123456789このとき、平均ベクトルは [4, 5, 6] となります。これは、各列の平均値がそれぞれ次のように計算されるためです。1列目:(1 + 4 + 7) / 3 = 42列目:(2 + 5 + 8) / 3 = 53列目:(3 + 6 + 9) / 3 = 6この例からも分かるように、行列の平均ベクトルとは「各列の平均値を要素として持つベクトル」のことです。したがって、行列の各列ごとに平均を計算し、その結果を順に並べるだけで平均ベクトルを求められます。
-
C++で配列要素の階乗の最大公約数(GCD)を求める方法
N個の要素を持つ配列Aが与えられたとき、配列内のすべての要素の階乗の最大公約数(GCD)を求めることを考えます。例えば、配列の要素が {3, 4, 8, 6} の場合、各要素の階乗は 3! = 6、4! = 24、8! = 40320、6! = 720 となり、これらのGCDは 6 になります。解法のポイントここで重要な数学的な性質があります。2つの数のGCDとは、両方の数を割り切る最大の数のことです。階乗の場合、小さい数の階乗は必ず大きい数の階乗を割り切ることができます。つまり、2つの階乗のGCDは、小さい方の数の階乗そのものになります。例えば、3! と 5! のGCDを考えると、3! =