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

C++で配列の合計を奇数にするための最小削除数を求める方法


問題文

N個の整数からなる配列 arr[] が与えられます。残りの要素の合計が奇数になるように配列から要素を取り除くとき、削除が必要な要素数の最小値を求めるプログラムを作成しましょう。

入力配列が {10, 20, 30, 5, 7} の場合について考えてみます。この配列の合計は 72 という偶数であるため、合計を奇数にするには要素を1つ削除する必要があります。具体的には、「5」または「7」のいずれかを取り除けば条件を満たせます。

アルゴリズム

この問題は、偶数と奇数の足し算に関する以下の基本的な性質を利用すると効率的に解くことができます。

  1. 偶数をいくつ足し合わせても、その合計は必ず偶数になる
  2. 奇数を奇数個足し合わせた場合、合計は必ず奇数になる
  3. 奇数を偶数個足し合わせた場合、合計は必ず偶数になる
  4. 以上より、配列内の奇数の要素数をカウントする。カウントが偶数であれば合計も偶数になるため要素を1つ削除する必要があり、カウントが奇数であれば合計はすでに奇数なので要素を削除する必要はない

C++での実装例

#include <bits/stdc++.h>
using namespace std;

int getMinRemovals(int *arr, int n) {
    int cnt = 0;
    for (int i = 0; i < n; ++i) {
        if (arr[i] % 2 == 1) {
            ++cnt;
        }
    }
    return (cnt % 2 == 0) ? 1 : 0;
}

int main() {
    int arr[] = {10, 20, 30, 5, 7};
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << "Minimum required removals = " <<
    getMinRemovals(arr, n) << endl;
    return 0;
}

実行結果

上記のプログラムをコンパイルして実行すると、次のような出力が得られます。

Minimum required removals = 1

計算量

このアルゴリズムは配列を一度だけ走査して奇数の個数を数えるため、時間計算量は O(N)、追加のメモリを必要としないため空間計算量は O(1) となります。

注意点

配列に奇数の要素が1つも含まれていない場合(すべての要素が偶数の場合)、どの要素を削除しても合計は偶数のままとなり、合計を奇数にすること自体が不可能です。上記のサンプルコードではこのケースが考慮されていないため、実務で利用する際には奇数要素が存在するかどうかのチェックを追加しておくとより安全です。

  1. C++で解く合計配列パズル|自身を除いた要素の総和を効率的に求める方法

    配列(Array)とは 配列とは、同じデータ型の複数の要素をまとめて格納できるデータ構造です。複数の値を一度に扱えるのが大きな特徴ですが、その長さはあらかじめ定義しておく必要があります。 合計配列パズルとは このパズルでは、サイズ n の配列 A1 が与えられます。これを解くために、配列 S1 を作成します。S1 には、対応する位置の要素を除いた A1 の全要素の合計を格納します。たとえば S1[3] を計算する場合、A1 の 4 番目の要素(インデックス 3)以外のすべての要素の合計を求めることになります。 具体例 配列 A1 = {1, 2, 3, 4, 6} 出力 S1 = {15, 1

  2. 【C++】配列を互いに素な配列に変換するための最小挿入回数を求める方法

    問題の概要 今回は、与えられた配列を互いに素な配列(コプライム配列)に変換するために必要な最小の挿入回数を求める、興味深い問題を取り上げます。互いに素な配列とは、隣り合う任意の2つの要素の最大公約数(GCD)が必ず1になる配列のことです。この記事では、必要な挿入回数に加えて、変換後の配列そのものも出力します。 例として、{5, 10, 20} という配列を考えてみましょう。この配列は隣接要素同士のGCDが5や10となるため、互いに素な配列ではありません。しかし、5と10の間、そして10と20の間にそれぞれ「1」を挿入すれば、{5, 1, 10, 1, 20} となり、すべての隣接ペアのGCD