C/C++で解く:配列の要素を置き換えて合計値Sと一致させる値Kの求め方
問題の概要
ここでは、配列に関する興味深い問題を扱います。n 個の要素からなる配列と、目標となる合計値 S が与えられます。このとき、次の条件を満たす値 K を配列の中から見つける必要があります。
「配列内の K より大きい要素をすべて K に置き換えたとき、最終的な配列の全要素の合計がちょうど S と等しくなる」。もし条件を満たす K が存在しない場合は、-1 を返します。
例として、配列 {12, 6, 3, 7, 8} と合計値 15 が与えられたケースを考えてみましょう。このときの出力は 3 になります。なぜなら、3 より大きい要素をすべて 3 に置き換えると、配列は {3, 3, 3, 3, 3} となり、その合計はちょうど S = 15 となるからです。
アルゴリズム
getVal(arr, n, S) の処理手順は以下の通りです。
開始
配列 arr を昇順にソートする
sum := 0
i を 0 から n-1 まで繰り返す:
もし sum + (arr[i] * (n - i)) が S と等しいならば
return arr[i]
終了
sum := sum + arr[i]
ループ終了
return -1
終了
アルゴリズムの考え方
このアルゴリズムのポイントは、配列をあらかじめ昇順にソートしておくことです。ソート後の配列を先頭から走査するとき、インデックス i より前の要素(arr[0] 〜 arr[i-1])は確定済みとして変数 sum に加算されています。また、残りの n - i 個の要素はすべて arr[i] 以上の値を持っているため、「arr[i] 以降をすべて arr[i] に置き換えた場合の合計」は「sum + arr[i] × (n - i)」という式で一括計算できます。この値が目標の S と一致すれば、その位置の要素 arr[i] こそが求める K です。
計算量はソート部分が支配的となり、時間計算量は O(n log n)、追加のメモリは O(1) で済むため、非常に効率的な手法といえます。
C++での実装例
#include <iostream>
#include <algorithm>
using namespace std;
int getVal(int arr[], int n, int S) {
sort(arr, arr + n);
int sum = 0;
for (int i = 0; i < n; i++) {
if (sum + (arr[i] * (n - i)) == S) // 条件を満たす場合は現在の値を返す
return arr[i];
sum += arr[i];
}
return -1;
}
int main() {
int S = 15;
int arr[] = { 12, 3, 6, 7, 8 };
int n = sizeof(arr) / sizeof(arr[0]);
cout << getVal(arr, n, S);
}
実行結果
3
まとめ
本記事では、配列を昇順にソートしながら累積和を利用することで、条件を満たす値 K を効率的に求める方法を紹介しました。ソートにより「それ以降の要素をまとめて置き換えた場合の合計」を O(1) で判定できるのが最大のポイントです。同様のパターンは、二分探索や累積和を使う他の配列問題にも応用できるので、ぜひ理解しておきましょう。
-
C/C++でpthreadを使ったマトリックス(行列)の加算・減算をマルチスレッドで実装する方法
本記事では、マルチスレッド環境を活用して行列(マトリックス)の加算と減算を行う方法を解説します。C/C++では、POSIXスレッド(pthread)を使用することで、複数のスレッドを同時に実行でき、大規模な行列演算の処理時間を短縮できます。 基本的な考え方 ここでは2つの行列AとBを用意し、それぞれのサイズは m × n とします。各スレッドが担当する行を受け持ち、その行に対して加算または減算を計算します。サンプルコードでは、コア数を3(CORE=3)とし、加算用に3スレッド、減算用に3スレッドの合計6スレッドを生成して、行列全体を3分割して並列処理しています。 サンプルコード #incl
-
マージソートを使って配列の転倒数(反転数)を数えるC/C++プログラム
転倒数(Inversion Count)とは?与えられた配列をソートする際に発生する反転(転倒)の回数を「転倒数(Inversion Count)」と呼びます。転倒数を求める問題は古典的なアルゴリズム問題の一つで、マージソート(Merge Sort)のアルゴリズムを応用することで効率的に解くことができます。この問題では、各要素について「自分より左側にあり、かつ自分より大きな値を持つ要素」の数をすべて数え上げ、その合計を出力します。この処理は、マージソートのマージ(merge)関数の中で実装されます。理解を深めるために、マージ処理で扱う2つの部分配列を例に考えてみましょう。配列の転倒数の定義配列