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

C++で配列内の最大トリプレット合計を求める方法(i < j < k かつ a[i] < a[j] < a[k] の条件付き)

概要

サイズ n の正整数からなる配列が与えられたとき、0 <= i < j < k < n かつ ai < aj < ak を満たすトリプレット(ai + aj + ak)の中で最大の合計値を求めるのが本記事の課題です。

入力例

a[] = 3 6 4 2 5 10

出力例

19

説明

考えられるすべてのトリプレットは以下の通りです。
3 4 5 => 合計 = 12
3 6 10 => 合計 = 19
3 4 10 => 合計 = 17
4 5 10 => 合計 = 19
2 5 10 => 合計 = 17
最大合計 = 19

解法アプローチ

単純なアプローチ(ブルートフォース)

最もシンプルな方法は、3重の for ループですべてのトリプレットを順に調べ、それぞれの合計を計算して最大値を更新していくものです。しかし、この方法の時間計算量は O(n³) となるため、n が大きくなると実用性に欠けます。

改善されたアプローチ(O(n²))

上記の方法をさらに最適化するために、3重ループの代わりに2重ループで走査する方法が有効です。

具体的には、各要素を「中央の要素(aj)」とみなし、以下の手順で処理します。

  • その要素より前にある要素の中から、aj より小さい値の最大値(ai)を求める。
  • その要素より後ろにある要素の中から、aj より大きい値の最大値(ak)を求める。

両方が存在する場合のみ、合計 ai + aj + ak を計算し、これまでの最大値と比較して答えを更新します。この方法の時間計算量は O(n²) であり、単純なアプローチよりも大幅に高速化できます。

C++による実装例

// C++プログラム:最大トリプレット合計を求める
#include <bits/stdc++.h>
using namespace std;

// 最大トリプレット合計を計算する関数
int maxTripletSum(int arr1[], int n1){
    // 答えを初期化
    int ans1 = 0;
    for (int i = 1; i < n1 - 1; ++i) {
        int max1 = 0, max2 = 0;
        // arr1[i] より小さい最大値を求める(0 ~ i-1 の範囲)
        for (int j = 0; j < i; ++j)
            if (arr1[j] < arr1[i])
                max1 = max(max1, arr1[j]);
        // arr1[i] より大きい最大値を求める(i+1 ~ n1-1 の範囲)
        for (int j = i + 1; j < n1; ++j)
            if (arr1[j] > arr1[i])
                max2 = max(max2, arr1[j]);
        // 左右どちらも候補が存在する場合のみ答えを更新
        if(max1 && max2)
            ans1 = max(ans1, max1 + arr1[i] + max2);
    }
    return ans1;
}

// ドライバーコード
int main(){
    int Arr[] = { 3, 6, 4, 2, 5, 10 };
    int N = sizeof(Arr) / sizeof(Arr[0]);
    cout << maxTripletSum(Arr, N);
    return 0;
}

実行結果

19

まとめ

この問題では、各要素を中央の要素として扱うことで、必要な探索範囲を左右に分割でき、計算量を O(n³) から O(n²) へ削減できます。さらに、前方向の最大値や後ろ方向の最大値を事前に配列へキャッシュしておくことで、追加の最適化も可能です。競技プログラミングやアルゴリズム学習において、こうした「中央要素固定」の発想は応用範囲が広いため、ぜひ覚えておきましょう。

  1. C++で長さm以下となる最大合計部分配列を求めるアルゴリズム

    この問題では、長さの異なる n 個の配列が与えられます。求めるのは、合計長さが m 以下となるように各配列から部分配列を選択し、その要素の合計を最大化することです。つまり、複数の配列の中から部分配列を取り出し、それら全体の合計値を最大化しながら、選んだ部分配列の長さの総和を m 以内に収める必要があります。問題例具体的な入力と出力を見て、問題を理解しましょう。入力n = 3, m = 4 arrOfArr[][] = { {5, 2, -1, 4, -3}, {3, -2, 1, 6}, {-2, 0, 5} }出力20解説選択した部分配列:{5, 4}, {6}, {

  2. C++で二分木の最大レベル和を求める方法

    問題概要 この問題では、正と負の値を含む二分木が与えられます。私たちのタスクは、二分木におけるレベル和の最大値を見つけることです。 問題の説明: 与えられた二分木に対して、各レベルに存在するすべてのノードの値の合計を計算し、その中で最も大きい値を返します。 具体例を使って問題を理解しましょう。 入力: 出力: 5 説明: レベル1の要素の合計:3 レベル2の要素の合計:-3 + 4 = 1 レベル3の要素の合計:5 - 1 + 6 - 5 = 5 各レベルの合計は「3」「1」「5」となるため、最大のレベル和は 5 となります。 解法アプローチ この問題を効率的に解くには、レベル順走査(幅優先