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

C++で部分配列を1回だけ反転して0の個数を最大化する方法

問題文

0と1のみから構成される2値配列(バイナリ配列)が与えられます。ここで、部分配列を1回だけ反転できるという条件のもとで、配列全体に含まれる0の個数を最大化することを考えます。

なお、反転操作とは、指定した範囲内のすべての0を1に、1を0に切り替える処理のことです。

具体例

次の配列を考えてみましょう。

arr = {1, 1, 0, 0, 0, 0, 0}

先頭の2つの「1」を「0」に反転すると、配列全体が次のようになります。

{0, 0, 0, 0, 0, 0, 0}

この場合、0の個数は7となり、これが最大値です。

解法のポイント

ある部分配列を反転すると、その範囲内の1は0に、0は1に変わります。したがって、反転後の0の総数は次の式で表せます。

最終的な0の個数 = 元の配列の0の個数 + (部分配列内の1の個数 − 部分配列内の0の個数)

つまり、「1の個数 − 0の個数」が最大となる部分配列を見つければよいことになります。

アルゴリズム

  1. すべての部分配列を調べ、「1の個数 − 0の個数」の値が最大になる部分配列を探します。
  2. この最大値を maxDiff とします。
  3. 最終的な答えとして、元の配列の0の個数 + maxDiff を返します。

この手法の計算量は、全ての開始位置・終了位置の組み合わせを調べるため O(n²) となります。

C++での実装例

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

int getMaxSubArray(int *arr, int n){
    int maxDiff = 0;
    int zeroCnt = 0;
    for (int i = 0; i < n; ++i) {
        if (arr[i] == 0) {
            ++zeroCnt;
        }
        int cnt0 = 0;
        int cnt1 = 0;
        for (int j = i; j < n; ++j) {
            if (arr[j] == 1) {
                ++cnt1;
            }
            else {
                ++cnt0;
            }
            maxDiff = max(maxDiff, cnt1 - cnt0);
        }
    }
    return zeroCnt + maxDiff;
}

int main(){
    int arr[] = {1, 1, 0, 0, 0, 0, 0};
    int n = sizeof(arr) / sizeof(arr[0]);
    cout << "Maximum subarray size = " << getMaxSubArray(arr, n) << endl;
    return 0;
}

実行結果

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

Maximum subarray size = 7

まとめ

本記事では、2値配列に対して部分配列を1回だけ反転できる場合に、0の個数を最大化する方法を紹介しました。鍵となるのは「反転によって増える0の数=部分配列内の(1の個数 − 0の個数)」という着眼点です。全部分配列を走査するO(n²)のシンプルな実装で正しく解くことができます。

  1. C++で可変数の引数(可変長引数)を扱う方法

    プログラミングをしていると、引数の個数があらかじめ決まっていない関数、つまり呼び出しのたびに異なる数のパラメータを受け取れる関数が必要になる場面があります。C/C++ではこのような状況に対応する仕組みが用意されており、要件に応じて可変個の引数を受け取る関数を自由に定義できます。以下に、そのような関数の定義例を示します。 int func(int, ... ) { . . . } int main() { func(1, 2, 3); func(1, 2, 3, 4); } 注目すべきは、関数func()の最後の引数が省略記号(ピリオド3つの「...」)になってい

  2. C++のCHAR_BITとは?意味と使い方を解説

    CHAR_BITは、char型が持つビット数を表すマクロです。C++では「limits.h」ヘッダーファイル(C++では<climits>)で宣言されており、一般的な環境では1バイトが8ビットであることを示します。このマクロを利用することで、移植性の高いコードを書くことができます。環境に依存せずにchar型のビット数を取得できるため、ビット演算やデータサイズの計算に役立ちます。CHAR_BITの使用例以下は、C++でCHAR_BITを使用したサンプルコードです。CHAR_BITとsizeofを組み合わせてint型の全ビット数を求め、整数値を2進数形式で出力しています。#includ