Pythonで最長のチャンク回文分解の長さを求めるプログラム
この記事では、与えられたテキストに対して「チャンク回文分解」の最大分割数 k を求める問題を、Pythonを使って解く方法を解説します。
問題の定義
あるテキストが与えられたとき、次の条件をすべて満たすような最大の k を求めます。
- 各 a[i] は空文字列(ブランク)ではない
- 連結した文字列 a[1] + a[2] + ... + a[k] が元のテキストと一致する
- 1 ≤ i ≤ k のすべての i について、a[i] = a[k+1-i] が成り立つ(前から i 番目のチャンクと後ろから i 番目のチャンクが同じ)
具体例
たとえば、入力が text = "antaprezatepzapreanta" の場合、出力は 11 になります。これは、次のように11個のチャンクに分割できるためです。
a | nt | a | pre | za | tpe | za | pre | a | nt | a
前半の「a, nt, a, pre, za」と後半の「za, pre, a, nt, a」が対称になっており、中央の「tpe」が残る形になっているのがわかります。
解法のアルゴリズム
この問題は、両端から順に一致する部分を取り除いていく貪欲法(グリーディ法)で解けます。手順は以下の通りです。
- カウンター counter を 0 で初期化する
- i := 1、j := テキストの長さ - 1 とする
- ic := 0、jc := テキストの長さ とする
- i ≤ j の間、以下を繰り返す
- text[ic:i](左側の候補チャンク)と text[j:jc](右側の候補チャンク)が一致する場合、counter に 2 を加算し、ic := i、jc := j と更新する
- 各ステップで i を 1 増やし、j を 1 減らす
- ループ終了後、ic ≠ jc の場合は中央に余ったチャンクが存在するので、counter に 1 を加算する
- counter を返す
Pythonでの実装例
それでは、実際のコードを見てみましょう。
def solve(text):
counter = 0
i, j = 1, len(text) - 1
ic, jc = 0, len(text)
while i <= j:
if text[ic:i] == text[j:jc]:
counter += 2
ic = i
jc = j
i += 1
j -= 1
if ic != jc:
counter += 1
return counter
text = "antaprezatepzapreanta"
print(solve(text))入力
antaprezatepzapreanta
出力
11
計算量について
このアルゴリズムでは、ポインタ i と j が互いに近づきながら全文字を走査し、各ステップで部分文字列の比較を行います。最悪の場合、時間計算量は O(n²) となります。ただし、実用上は多くのケースで高速に動作します。
まとめ
チャンク回文分解の問題は、文字列の両端から対称なチャンクを貪欲に切り出していくことで効率的に解くことができます。ポイントは、左右の候補部分文字列が一致したタイミングで境界を確定させ、最後に中央に残った部分を1チャンクとして数える点です。
-
Pythonで「a」から始まる連続増加部分文字列の最長長さを求めるプログラム
問題の概要小文字の英字と「?」記号を含む文字列 s が与えられます。各「?」については、削除するか、任意の小文字の英字に置き換えることができます。このとき、「a」で始まる連続して増加する部分文字列(例:abcdef のようにアルファベット順に1文字ずつ進む文字列)の最長の長さを求める必要があります。例えば、入力が s = vta???defke の場合、出力は 6 になります。これは、s を vtabcdefke に変換できるためです。変換後の文字列には abcdef という連続増加部分文字列が含まれており、これが「a」で始まる最長のものとなります。解法のアプローチこの問題は、文字列を一度走査
-
Pythonでn分木の最長パスの長さを求めるプログラムの書き方
各要素が (u, v) という形式を持ち、u が v の親であることを表す辺リストが与えられているとします。このとき、木の中で最も長いパスの長さを求める必要があります。ここでいうパスの長さとは、「そのパスに含まれるノードの総数 + 1」のことです。 たとえば、入力が下図のような n 分木だった場合を考えてみましょう。 この場合の出力は 5 になります。なぜなら、パス [1, 4, 5, 7] には合計 4 つのノードが含まれており、パスの長さは 1 + 4 = 5 となるからです。 解き方のアプローチ この問題は、幅優先探索(BFS)を2回実行するという定番テクニックで効率よく解けます。まず