C++で配列内の重複しない(一意な)要素の合計を求める方法
問題の概要
いくつかの要素を含む配列 A があるとします。この配列から、すべての一意な(重複しない)要素の合計を求める必要があります。
例えば、配列が A = [5, 12, 63, 5, 33, 47, 12, 63] の場合を考えてみましょう。このとき、一意な要素は「5, 12, 63, 33, 47」であり、その合計は 160 になります。重複している要素は、一度合計に加算された後は単純に無視されます。
解決のアプローチ
この問題は、C++の unordered_set(ハッシュセット)を使うことで効率的に解決できます。基本的な考え方は以下のとおりです。
- forループを1回だけ実行して配列を走査する
- 初めて現れた値であれば、合計変数に加算する
- 同時にハッシュテーブル(unordered_set)にその値を記録する
- 2回目以降に同じ値が現れた場合は、すでにセットに存在するため無視する
ハッシュセットによる検索・挿入は平均 O(1) で行えるため、全体の計算量は O(n) となり、非常に高速に処理できます。
コード例
#include<iostream>
#include<unordered_set>
using namespace std;
int getNonRepeatSum(int arr[], int n) {
int sum = 0;
unordered_set<int> u_set;
for (int i = 0; i < n; i++) {
// まだセットに存在しない値なら加算して登録
if (u_set.find(arr[i]) == u_set.end()) {
sum += arr[i];
u_set.insert(arr[i]);
}
}
return sum;
}
int main() {
int arr[] = {5, 12, 63, 5, 33, 47, 12, 63};
int n = sizeof(arr) / sizeof(int);
cout << "Sum is: " << getNonRepeatSum(arr, n);
}実行結果
Sum is: 160
コードのポイント
u_set.find(arr[i]) == u_set.end()によって、その値がまだセットに存在しないこと(=初登場であること)を判定しています。- 初登場の値のみ
sumに加算し、insert()でセットに登録することで、以降の重複を自動的に排除できます。 - ソート不要・二重ループ不要のため、要素数が多い配列でも高いパフォーマンスを発揮します。
-
C++で配列のすべての部分集合(サブセット)の合計を求める方法
問題の概要整数の配列が与えられたとき、その部分集合(サブセット)から作り出せるすべての異なる合計値を求め、昇順に出力する方法を解説します。この問題は、配列の要素の合計値が比較的小さい場合に、動的計画法を使って効率的に解くことができます。例として、配列 [1, 2, 3] を考えてみましょう。考えられるすべての部分集合は {}、{1}、{2}、{3}、{1, 2}、{2, 3}、{1, 3}、{1, 2, 3} であり、それぞれの合計値は 0, 1, 2, 3, 3, 5, 4, 6 となります。重複する値を取り除くと、出力は 0, 1, 2, 3, 4, 5, 6 となります。アプローチ:動的
-
C++で2つの配列の合計を等しくする要素スワップのペアを見つける方法
要素数が異なる2つの配列があるとします。このとき、1つ目の配列に含まれる要素 x と、2つ目の配列に含まれる要素 y からなるペアを見つけます。このペアを選んで2つの配列間で要素を入れ替えた結果、両方の配列の合計が等しくなるようにするのが目的です。例として、配列 A が [4, 1, 2, 2, 1, 1]、配列 B が [3, 3, 6, 3] を持っている場合を考えてみましょう。A の合計は 11、B の合計は 15 です。ここで (1, 3) というペアを選び、これらの値を2つの配列間で入れ替えると、合計は次のようになります。A: [4, 3, 2, 2, 1, 1] → 合計 13B: