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

C++で左側をすべて1、右側をすべて0にするための最小反転回数を求める方法


問題文

「0」と「1」からなる2進文字列が与えられます。この文字列を反転(フリップ)して、左側をすべて「1」、右側をすべて「0」にするとき、必要となる最小の反転回数を求めるのが課題です。

与えられた2進文字列は「0010101」です。この文字列には「1」が3個、「0」が4個含まれています。下記のように4ビットを反転することで、左側がすべて「1」、右側がすべて「0」の文字列にすることができます。

0010101

反転後の文字列は次のとおりです。

1110000

アルゴリズム

  • 文字列を左から右へ走査し、各位置までの「0」をすべて「1」に変換するために必要な反転回数を累積的に計算します。
  • 文字列を右から左へ走査し、各位置からの「1」をすべて「0」に変換するために必要な反転回数を累積的に計算します。
  • 分割位置をすべて試し、「0の反転回数+1の反転回数」の合計が最小となる値を求めます。

実装例(C++)

#include <iostream>
#include <string>
#include <climits>
using namespace std;

int minFlips(string binaryString) {
    int n = binaryString.length();
    int flipCnt, zeroFlips[n], oneFlips[n];

    // 左から右へ走査し、各位置までの「0」を「1」にする反転回数を記録
    flipCnt = 0;
    for (int i = 0; i < n; ++i) {
        if (binaryString[i] == '0') {
            ++flipCnt;
        }
        zeroFlips[i] = flipCnt;
    }

    // 右から左へ走査し、各位置からの「1」を「0」にする反転回数を記録
    flipCnt = 0;
    for (int i = n - 1; i >= 0; --i) {
        if (binaryString[i] == '1') {
            ++flipCnt;
        }
        oneFlips[i] = flipCnt;
    }

    // 全ての分割位置について反転回数の合計を評価し、最小値を求める
    int minFlips = INT_MAX;
    for (int i = 1; i < n; ++i) {
        int sum = zeroFlips[i - 1] + oneFlips[i];
        if (sum < minFlips) {
            minFlips = sum;
        }
    }
    return minFlips;
}

int main() {
    string binaryString = "0010101";
    cout << "Minimum flips: " << minFlips(binaryString) << endl;
    return 0;
}

計算量

このアルゴリズムは文字列を3回走査するだけで済むため、時間計算量は O(n)、補助配列2つを使用するため空間計算量も O(n) となります。文字列の長さが大きい場合でも効率的に動作します。

出力

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

Minimum flips: 4

  1. C++で二分木のすべての葉ノードを右から左の順に出力する方法

    問題概要この記事では、二分木(binary tree)が与えられたとき、そのすべての葉ノード(リーフノード)を右から左の順で出力する方法を解説します。まず、具体例を使って問題を確認しましょう。入力例出力例7 4 1この問題を解くには、二分木を走査(トラバース)する必要があります。走査のアプローチは主に次の2つがあります。方法1:前順走査(Preorder Traversal)+ 再帰前順走査は再帰を用いた手法で、通常は「根 → 左部分木 → 右部分木」の順にノードを訪問します。ただし今回は右から左へ出力する必要があるため、再帰呼び出しの順序を「右部分木 → 左部分木」にするのがポイントです。葉

  2. C++の演算子の優先順位と結合規則を徹底解説【一覧表付き】

    演算子の優先順位とはC++における演算子の優先順位(operator precedence)は、式の中で各項(オペランド)がどのようにグループ化されるかを決める重要なルールです。また、結合規則(associativity)とは、括弧がない場合に同じ優先順位を持つ演算子がどちらの方向から評価されるかを決める特性のことを指します。これらは式の評価結果に直接影響を与えます。演算子によって優先順位には差があり、一部の演算子は他の演算子よりも先に評価されます。たとえば、乗算演算子(*)は加算演算子(+)よりも高い優先順位を持っています。具体例:x = 7 + 3 * 2 の評価x = 7 + 3 * 2