C++で2つの要素の和が3番目の要素と等しくなるトリプレットを見つける方法
n個の数値からなる配列があるとします。この中から「2つの要素の和が、もう1つの要素と等しくなる」ような3つの数値(トリプレット)を見つける必要があります。
例えば、配列が [5, 32, 1, 7, 10, 50, 19, 21, 2] の場合、出力は 21, 2, 19 となります(2 + 19 = 21)。該当する組み合わせが存在しない場合は、その旨のメッセージを表示します。
アルゴリズムの考え方
この問題を解決するには、以下の手順に従います。
- まず、与えられた配列を昇順にソートします。
- 次に、配列の末尾(最大の要素)から順に要素を固定し、その要素と等しくなるような和を持つ2つの数値を探索します。
- 2つのポインタ j(先頭から)と k(i - 1 の位置から)を用意し、範囲内の最小値と最大値を効率よく探します。
- 2つの数値の和が Arr[i] より小さい場合は、和を増やす必要があるため、ポインタ j を1つ進めます(これにより Arr[j] + Arr[k] の値が大きくなります)。
- 2つの数値の和が Arr[i] より大きい場合は、和を減らす必要があるため、ポインタ k を1つ戻します(これにより Arr[j] + Arr[k] の値が小さくなります)。
この手法により、ソート後の配列に対して各要素を固定しながら2ポインタ法を適用することで、効率的にトリプレットを発見できます。
サンプルコード
#include<iostream>
#include<algorithm>
#define N 5
using namespace std;
void getValueTriplet(int arr[], int n) {
sort(arr, arr + n);
for (int i = n - 1; i >= 0; i--) {
int j = 0;
int k = i - 1;
while (j < k) {
if (arr[i] == arr[j] + arr[k]) {
cout << "The numbers are " << arr[i] << " " << arr[j] << " " << arr[k] << endl;
return;
}
else if (arr[i] > arr[j] + arr[k])
j += 1;
else
k -= 1;
}
}
cout << "No such triplet exists";
}
int main() {
int arr[] = { 5, 32, 1, 7, 10, 50, 19, 21, 2 };
int n = sizeof(arr) / sizeof(arr[0]);
getValueTriplet(arr, n);
}実行結果
The numbers are 21 2 19
計算量について
このアルゴリズムの時間計算量は、ソートに O(n log n)、その後の探索に O(n²) かかるため、全体として O(n²) となります。素朴な全組み合わせを試す方法(O(n³))と比較して、大幅に効率化されている点がポイントです。
-
【C++】循環配列で隣接しない要素を選んだときの最大合計を求める方法
問題の概要本記事では、循環配列 cirArr[] が与えられたとき、「どの2つの要素も隣接して選ばない」という条件を満たす要素の最大合計を求めるプログラムをC++で作成します。問題の詳細循環配列に対して、隣接する要素を同時に選ぶことができない、つまり要素を一つ飛ばしで選択した場合の最大合計を求める必要があります。循環配列とは、配列の末尾の要素が先頭の要素につながっている特殊な配列構造のことです。具体例で問題を確認しましょう。入力例cirArr[] = {4, 1, 5, 3, 2}出力例9解説最大の合計となる循環部分列は [4, 5, 2] で、その合計は 9 になります。解決アプローチこの問
-
各要素がN以下となる一意なペアを見つけるC++プログラム
この記事では、要素がN以下であり、かつ以下の条件を満たす一意な数のペアを見つけるプログラムについて詳しく解説します。2つの数の差の2乗が、それらの最小公倍数(LCM)と等しいこと。2つの数の最大公約数(HCF)が、連続する2つの数の積として表せること。問題を解くためのアプローチこの問題を効率的に解くには、1から始まる連続する2つの数を取り、その積の倍数を順に調べる方法が有効です。その中からペアを特定するために、候補となる2つの数が最初の条件(差の2乗 = LCM)を満たしているかどうかを確認します。具体例:2と3の場合まず、2と3という連続する数を考えてみましょう。その積は6です。6の倍数を順