Pythonでバイナリ文字列を並べ替えて0と1が交互に並ぶようにできるか判定する方法
問題の概要
長さ2以上のバイナリ文字列 s が与えられたとき、その文字列を並べ替えることで、0と1が交互に並んだ文字列(オルタネート文字列)を作れるかどうかを判定する問題です。
例えば、入力が s = "1000111" の場合、「1」が4個、「0」が3個含まれているため、これらを並べ替えて "1010101" を作ることができます。したがって、出力は True になります。
解法の考え方
0と1が交互に並ぶ文字列では、文字列の長さによって「0」と「1」の出現回数の関係が一意に決まります。
- 長さが偶数の場合:「0」と「1」の出現回数は必ず等しくなります(例:"0101" → 0が2個、1が2個)。
- 長さが奇数の場合:どちらか一方の文字が、もう一方よりちょうど1個多くなります(例:"10101" → 1が3個、0が2個)。
この性質を利用すると、実際に並べ替えを試みる必要はなく、各文字の出現回数を数えるだけで判定できます。手順は以下の通りです。
- 文字列
s内の「1」の出現回数(one_count)を数えます。 - 文字列
s内の「0」の出現回数(zero_count)を数えます。 sの長さが偶数の場合:one_count と zero_count が一致すればTrue、そうでなければFalseを返します。sの長さが奇数の場合:|one_count − zero_count| が 1 であればTrue、そうでなければFalseを返します。
実装例
以下はPythonによる実装例です。str.count() メソッドを使うことで、各文字の出現回数を簡単に取得できます。
def solve(s):
one_count = s.count('1')
zero_count = s.count('0')
if len(s) % 2 == 0:
return (one_count == zero_count)
return abs(one_count - zero_count) == 1
s = "1000111"
print(solve(s))
入力
"1000111"
出力
True
計算量の評価
このアルゴリズムは、文字列を一度走査して各文字の出現回数を数えるだけなので、時間計算量は O(n)、追加の記憶領域は O(1) で済みます(n は文字列の長さ)。文字列の長さが大きくなっても効率的に動作する点が魅力です。
-
Pythonでベクトルxを90度回転・加算してベクトルyに到達できるか判定するアルゴリズム
2次元平面上に3つのベクトル x、y、z があるとします。ベクトル x を起点として、「90度(時計回り)の回転」または「ベクトル z の加算」を必要な回数だけ繰り返すことで、ベクトル y に到達できるかどうかを判定するのがこの問題です。 たとえば、入力が x = (-4, -2)、y = (-1, 2)、z = (-2, -1) である場合、出力は True になります。x に対して z を加算する操作と 90 度の時計回り回転を組み合わせることで、y = (-1, 2) の位置に到達できるからです。 解法のアプローチ この問題は、次の手順に沿って解くことができます。 1. util()
-
PythonでDFAを使って2進数文字列が3の倍数かどうかを判定する方法
はじめに ある数の2進表現を配列 n として受け取り、その値が3で割り切れるかどうかを「決定性有限オートマトン(DFA)」を使って判定する問題を考えてみましょう。 例えば、入力が n = [1, 1, 0, 0](10進数の12に相当)であれば、12は3の倍数なので出力は True になります。 DFAによるアプローチ この問題は、次のようなDFAを構築することで解けます。 考え方はシンプルです。ある数が3で割り切れるとき余りは0になり、割り切れない場合は余りが1または2になります。そこで、これら3つの余り(0・1・2)に対応する3つの状態を用意します。初期状態は余り0を表すため、同時に受理