C++でバイナリ文字列から1つの要素を削除してXORをゼロにする方法
問題の概要
この問題では、0と1だけで構成されたバイナリ文字列が与えられます。求めたいのは、1つの要素を削除したときに文字列全体のXORがゼロになるような削除方法の総数です。
まずは具体例で問題を確認してみましょう。
入力例
n = 11010
出力例
3
入力文字列「11010」には「1」が3つ含まれています。このうちどれか1つの「1」を削除すると、残る「1」は2個(偶数)となり、全体のXORが0になります。削除できるのは「1」の位置が3か所なので、答えは3通りです。
解法の考え方
この問題を解くカギは、XOR演算の基本的な性質にあります。
- 偶数個の「1」に対してXORを取ると、結果は必ず0になる
- 奇数個の「1」に対してXORを取ると、結果は1になる
- 「0」はXORの結果にまったく影響しない
これらの性質から、次のルールが導けます。
- 「1」の個数が偶数の場合:文字列全体のXORはすでに0です。ここから任意の「0」を1つ削除してもXORは変わらないため、答えは「0」の個数になります。
- 「1」の個数が奇数の場合:「1」を1つ削除すると残りの「1」が偶数個になり、XORが0になるため、答えは「1」の個数になります。
つまり、文字列を一度走査して「1」と「0」の個数を数えるだけで答えが求まります。
C++による実装
上記のロジックを実装したプログラムが以下のとおりです。
#include<iostream>
#include<string>
using namespace std;
int wayXorZero(string binaryString){
int oneCount = 0, zeroCount = 0;
int n = binaryString.length();
// 「1」と「0」の個数をそれぞれカウント
for (int i = 0; i < n; i++) {
if (binaryString[i] == '1')
oneCount++;
else
zeroCount++;
}
// 「1」が偶数個なら「0」の個数、奇数個なら「1」の個数を返す
if (oneCount % 2 == 0)
return zeroCount;
return oneCount;
}
int main(){
string binaryString = "10110100";
cout<<"XORをゼロにする方法の数:"<<wayXorZero(binaryString);
return 0;
}
実行結果
XORをゼロにする方法の数:4
入力文字列「10110100」には「1」が4個(偶数)、「0」が4個含まれています。「1」の個数が偶数のため、XORを0のまま保てるのは「0」を削除する4か所であり、出力は4となります。
コードの解説
関数 wayXorZero() の処理の流れは次のとおりです。
- 文字列を先頭から順に走査し、「1」の個数(oneCount)と「0」の個数(zeroCount)をカウントします。
- 「1」の個数が偶数であれば、XORはすでに0になっているため「0」の個数を返します。
- 「1」の個数が奇数であれば、「1」の個数をそのまま返します。
計算量
- 時間計算量:O(n) ― 文字列を1回だけ走査します(nは文字列の長さ)。
- 空間計算量:O(1) ― カウンタ用の整数変数2つのみを使用します。
まとめ
バイナリ文字列から1つの要素を削除してXORをゼロにする問題は、「1」の出現回数の偶奇に着目することが重要です。「1」が偶数個なら答えは「0」の個数、奇数個なら答えは「1」の個数というシンプルなルールにより、O(n)の線形時間で効率的に解くことができます。
-
C++で文字列から二分木を構築する方法
括弧と整数から構成される文字列が与えられたとき、その文字列から二分木を構築する問題を考えてみましょう。入力文字列全体が一つの二分木を表しており、整数の後に0個、1個、または2組の括弧が続く形式になっています。整数はルート(根)ノードの値を表し、各括弧のペアは同じ構造を持つ子の部分木を含んでいます。問題の例例えば、入力が 4(2(3)(1))(6(5)) のような文字列だった場合、出力は [3,2,1,4,5,6](中順走査・inorder traversal の結果)となります。解決アプローチこの問題を解くために、以下の手順に従います。再帰関数 solve() を定義します。引数として文字列
-
C++でstd::stringから空白を削除する方法
```html この記事では、C++でstd::stringから空白(スペース)を取り除く方法を解説します。空白の削除には、<algorithm>ヘッダーで提供されるremove()関数を使用します。この関数は、処理対象の範囲の先頭と末尾を指す2つのイテレータと、削除したい値を第3引数として受け取ります。入力:文字列 "This is C++ Programming Language" 出力:文字列 "ThisisC++ProgrammingLanguage"アルゴリズムステップ1:文字列を取得する ステップ2:remove()関数を使って、