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

【C++】配列内のK番目ごとの要素を取得したときの最大合計を求める方法

この記事では、配列 arr[] と整数 k が与えられたとき、「K番目ごとの要素を取得して得られる合計」の最大値を求めるアルゴリズムについて解説します。

問題の概要

配列の要素のうち、インデックスが k ずつ離れている要素だけを選んで合計し、その合計が最大になるようにします。つまり、次の式で表される sum を最大化することが目的です。

sum = arr[i] + arr[i+k] + arr[i+2*k] + … + arr[i+p*k](条件:i + p*k < n)

入出力例

入力:

arr[] = {5, 3, −1, 2, 4, −5, 6}, k = 4

出力:

9

説明:

各開始位置から k 個おきに要素を取得した場合の合計は以下のようになります。

5 + 4 = 9
3 − 5 = −2
−1 + 6 = 5
2
4
−5
6

これらの中で最大となるのは 9 です。

解法アプローチ①:二重ループによるシンプルな解法(計算量 O(n²))

最も単純な方法は、外側のループで各開始位置 i を走査し、内側のループで「i から始めて k 個おきに要素を加算した合計」を計算する方法です。すべての開始位置について合計を求め、その中の最大値を返します。

実装例

#include <iostream>
using namespace std;

int findMaxSumK(int arr[], int n, int K){
    int maxSum = -1000;
    for (int i = 0; i < n; i++) {
        int current_Sum = 0;
        for (int j = i; j < n; j += K)
            current_Sum += arr[j];
        maxSum = max(maxSum, current_Sum);
    }
    return maxSum;
}

int main(){
    int arr[] = {5, 3, -1, 2, 4, -5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);
    int K = 3;
    cout << "配列内のK番目ごとの要素を取得したときの最大合計は "
         << findMaxSumK(arr, n, K);
    return (0);
}

出力

配列内のK番目ごとの要素を取得したときの最大合計は 13

この方法は直感的で分かりやすい反面、すべての開始位置に対して再度合計を計算するため、時間計算量は O(n²) となり、配列が大きい場合は非効率です。

解法アプローチ②:接尾辞和(Suffix Sum)を使った効率的な解法(計算量 O(n))

より効率的な方法として、接尾辞和 を利用する手法があります。これは、各位置 i から「k 個おきに要素を取得した合計」を後ろから順に計算していく方法です。

具体的には、次の漸化式に従って配列 suffSum[] を埋めていきます。

  • i + K < n の場合:suffSum[i] = suffSum[i + K] + arr[i]
  • それ以外の場合:suffSum[i] = arr[i]

このようにすると、各位置からの合計を一度の走査で求められるため、時間計算量は O(n) に抑えられます。

実装例

#include <iostream>
using namespace std;

int findMaxSumK(int arr[], int n, int K) {
    int maxSum = -1000;
    int suffSum[n];
    for (int i = n - 1; i >= 0; i--) {
        if (i + K < n)
            suffSum[i] = suffSum[i + K] + arr[i];
        else
            suffSum[i] = arr[i];
        maxSum = max(maxSum, suffSum[i]);
    }
    return maxSum;
}

int main(){
    int arr[] = {5, 3, -1, 2, 4, -5, 6};
    int n = sizeof(arr) / sizeof(arr[0]);
    int K = 3;
    cout << "配列内のK番目ごとの要素を取得したときの最大合計は "
         << findMaxSumK(arr, n, K);
    return (0);
}

出力

配列内のK番目ごとの要素を取得したときの最大合計は 13

まとめ

解法時間計算量空間計算量特徴
二重ループO(n²)O(1)シンプルで理解しやすい
接尾辞和O(n)O(n)大規模な配列でも高速

小さな配列であれば二重ループでも十分ですが、パフォーマンスが重要な場面では接尾辞和を利用した O(n) の解法を採用するのがおすすめです。どちらのコードも同じ結果を出力するため、用途や制約に応じて使い分けましょう。

  1. C++で配列内の各要素に最も近い大きい値を効率的に検索する方法

    この記事では、配列内の各要素に対して「最も近い大きい値」を効率的に検索する方法を解説します。ある要素 x より大きい値が配列内に存在する場合、その中で最も小さい値(次に大きい要素)をその要素の答えとし、存在しない場合は -1 を出力します。例として、配列が {10, 5, 11, 10, 20, 12} の場合、結果は {11, 10, 12, 11, -1, 20} となります。最大値の 20 より大きい要素は配列内に存在しないため、20 に対しては -1 が出力されます。解決のアプローチこの問題は C++ STL の set(セット)を使うと簡単に解決できます。set は二分探索木をベース

  2. 配列の分割(パーティション)手法でk番目に小さい要素を見つけるC++プログラム

    本記事では、配列を分割(パーティション)する手法を用いて、配列内のk番目に小さい要素を求めるC++プログラムを解説します。この手法はクイックソートの考え方を応用したもので、配列全体をソートすることなく、目的の要素だけを効率的に特定できる点が特徴です。 アルゴリズム まず、ピボットを基準に配列を分割する CreatePartition() 関数と、その結果をもとにk番目に小さい要素が存在する範囲を再帰的に絞り込む Partition() 関数を使用します。 Begin 関数 CreatePartition() は 配列 a、下限 l、上限 h を引数にとる in := l、pi