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

【C++】そのサイズのすべてのサブ配列の合計がk以下となる最大サブ配列サイズの求め方

このチュートリアルでは、「そのサイズのすべてのサブ配列(部分配列)の合計がk未満となる、最大のサブ配列サイズ」を求めるプログラムについて解説します。

サイズNの配列と整数kが与えられます。求めるのは、与えられた配列内のその長さのすべてのサブ配列の合計がk以下となるようなサブ配列の長さです。

アルゴリズムの考え方

この問題は「累積和(プレフィックスサム)」と「二分探索」を組み合わせることで、O(N log N)の計算量で効率的に解くことができます。

解法の手順

1. 配列の累積和を事前に計算します。これにより、任意の区間の合計をO(1)で取得できます。
2. サブ配列の長さを候補として二分探索を行います。
3. 各候補の長さmidについて、その長さのすべてのサブ配列の合計がk以下であるかを累積和でチェックします。
4. 条件を満たす場合はより長い長さを、満たさない場合はより短い長さを探索します。

C++での実装例

#include<bits/stdc++.h>
using namespace std;
// 最大長のサブ配列を二分探索で求める
int bsearch(int prefixsum[], int n, int k) {
    int ans = -1;
    // 二分探索の実行
    int left = 1, right = n;
    while (left <= right) {
        int mid = (left + right) / 2;
        int i;
        for (i = mid; i <= n; i++) {
            if (prefixsum[i] - prefixsum[i - mid] > k)
                break;
        }
        if (i == n + 1) {
            left = mid + 1;
            ans = mid;
        }
        else right = mid - 1;
    }
    return ans;
}
// 最大サブ配列サイズを返す
int maxSize(int arr[], int n, int k) {
    int prefixsum[n + 1];
    memset(prefixsum, 0, sizeof(prefixsum));
    for (int i = 0; i < n; i++)
        prefixsum[i + 1] = prefixsum[i] + arr[i];
    return bsearch(prefixsum, n, k);
}
int main() {
    int arr[] = {1, 2, 10, 4};
    int n = sizeof(arr) / sizeof(arr[0]);
    int k = 14;
    cout << maxSize(arr, n, k) << endl;
    return 0;
}

出力

2

コードの解説

bsearch関数:二分探索により、条件を満たす最大のサブ配列長を求めます。長さmidのすべてのサブ配列がk以下であれば答えを更新し、より長い長さを探索します。

maxSize関数:累積和配列prefixsumを構築し、bsearchを呼び出します。prefixsum[i] - prefixsum[i - mid]を計算することで、長さmidのサブ配列の合計を即座に求められます。

実行結果の例:配列 {1, 2, 10, 4}、k = 14 の場合を考えます。長さ2のサブ配列 {1, 2}、{2, 10}、{10, 4} の合計はそれぞれ3、12、14であり、すべてk以下です。一方、長さ3のサブ配列 {2, 10, 4} の合計は16となりkを超えるため、答えは2になります。

  1. C++でmを法とする最大部分配列の総和を求めるアルゴリズム

    C++でmを法とする最大部分配列の総和とは この問題では、サイズnの整数型配列と整数mが与えられます。求めるのは、すべての部分配列の総和の中から、mで割った余りが最大となる値です。 問題の概要 − 各部分配列の全要素の合計をmで割った余りを計算し、その中で最大の値を求めます。 具体例で問題を確認しよう まずは例を見て、問題の内容を理解しましょう。 入力 − array = {4, 9, 2}、m = 6 出力 − 5 説明 − すべての部分配列と、それぞれを6で割った余りは以下の通りです。 {4}: 4 % 6 = 4 {9}: 9 % 6 = 3 {2}: 2 % 6 = 2 {4, 9}

  2. C++で絶対差が1以下となる要素の最大数を求める方法

    n個の要素からなる配列が与えられたとします。この配列から、選んだ任意の2つの要素の絶対差が1以下になるように、最大でいくつの要素を選べるかを求める問題です。例えば、配列が [2, 2, 3, 4, 5] の場合、答えは3となり、要素数が最大となる組み合わせは「2, 2, 3」です。解法の考え方絶対差が0または1であるということは、選べる数値は「x」と「x + 1」の2種類に限られることを意味します。そこで、各要素の出現回数(頻度)を記録しておき、隣り合う2つの値の頻度の合計が最大になるところを探せば、それが求める答えとなります。アルゴリズムの手順mapを使って、配列内の各要素の出現回数をカウン