【Python】文字列を回文に分割する方法の数を求めるアルゴリズムと実装
文字列 s が与えられたとき、その文字列を「すべての部分が回文になるように」分割する方法が何通りあるかを求める問題について解説します。
回文とは、前から読んでも後ろから読んでも同じになる文字列のことです。例えば「x」「yy」「xyyx」などはいずれも回文です。
問題の例
入力が s = "xyyx" の場合、出力は 3 になります。これは以下の3通りの分割方法が存在するためです。
- ["x", "yy", "x"]
- ["x", "y", "y", "x"]
- ["xyyx"]
解法のアプローチ(動的計画法)
この問題は動的計画法(DP)を使って効率的に解くことができます。ここでは、table[i] を「文字列の先頭から i 文字目までを回文に分割する方法の数」と定義して計算を進めます。
アルゴリズムの手順
- n := 文字列 s の長さ
- table := サイズ n+1 のリストを作成し、すべて 0 で初期化
- table[0] := 1(空文字列の分割方法は1通りとみなす)
- i を 0 から n まで繰り返す:
- j を 0 から i-1 まで繰り返す:
- sub := s[j:i](インデックス j から i までの部分文字列)
- もし sub が回文であれば、table[i] := table[i] + table[j]
- j を 0 から i-1 まで繰り返す:
- table の最後の要素を返す
Pythonでの実装例
class Solution: def solve(self, s): n = len(s) table = [1] + [0] * n for i in range(n + 1): for j in range(i): sub = s[j:i] if sub == sub[::-1]: table[i] += table[j] return table[-1] ob = Solution() s = "xyyx" print(ob.solve(s))
入力
"xyyx"
出力
3
コードのポイント
回文判定には sub == sub[::-1] という比較を使用しています。Python のスライス [::-1] は文字列を逆順にする操作なので、元の文字列と逆順の文字列が一致すれば、その部分文字列は回文であると判断できます。
計算量は O(n³) となります(n は文字列の長さ)。これは二重ループの中で部分文字列の切り出しと回文判定を行っているためです。文字列が長くなる場合は、事前に回文判定用のテーブルを作成しておくことで高速化することも可能です。
-
Pythonでグリッド上に集められるコインの最大数を求めるプログラム
問題の概要各セルにコインが置かれた2次元行列(マトリックス)があるとします。左上の [0,0] の位置からスタートし、右または下にのみ移動できるという制約のもとで、右下隅まで移動する過程で収集できるコインの最大数を求めるのがこの問題です。例として、次のような入力が与えられた場合を考えてみましょう。14226005この場合、出力は 14 になります。これは、パス [1, 4, 2, 2, 5] を通ることで、合計14枚のコインを集められるためです。解き方(動的計画法)この問題は動的計画法(DP)を使うと効率的に解けます。考え方はシンプルで、「あるセルに到達した時点でのコインの最大累積数」は、「そ
-
Pythonで階段の登り方の総数を求めるプログラムを作成する方法
プログラミングの典型的な問題として、「階段の登り方」問題があります。この記事では、Pythonを使ってこの問題を動的計画法(DP)で解く方法を詳しく解説します。 問題の概要 n段の階段があるとします。一度に1段または2段ずつ上ることができる場合、この階段を上るユニークな登り方の総数を返す関数を定義する必要があります。 ポイントは、段を踏む順序が異なれば別の登り方としてカウントするという点です。また、答えが非常に大きな数になる可能性があるため、結果を 10^9 + 7 で割った余りを返します。 例えば、入力が n = 5 の場合、出力は 8 となります。これは、次の8通りのユニークな登り方が存