Pythonで解く「最長チャンク回文分解」― 両端からの貪欲法アルゴリズム
問題の概要
ある文字列 text が与えられたとき、次の条件をすべて満たす最大の k を求める問題です。
- 各
a[i](i = 1〜k)は空でない文字列である - 連結した
a[1] + a[2] + ... + a[k]が、与えられたtextと完全に一致する - すべての i について
a[i] = a[k+1-i]が成り立つ(前後のチャンクが対称になっている)
たとえば、入力が "antaprezatepzapreanta" の場合、出力は 11 になります。これは次のように11個のチャンクへ分割できるためです。
(a)(nt)(a)(pre)(za)(tpe)(za)(pre)(a)(nt)(a)
解き方のアプローチ
この問題は、文字列の両端から同時に走査する貪欲法(グリーディ法)で効率的に解けます。左端から伸ばしていく部分文字列 temp1 と、右端から伸ばしていく部分文字列 temp2 が一致したタイミングで、そのペアを1組としてカウントしていきます。
アルゴリズムの手順
start := 0、end := 文字列長 - 1と初期化します。temp1とtemp2を空文字列で初期化します。ansを、文字列長が奇数なら 1、偶数なら 0 に設定します。start < endの間、以下を繰り返します。temp1 := temp1 + text[start]temp2 := text[end] + temp2temp1とtemp2が一致したら、両方を空文字列にリセットし、ans := ans + 2とします。start := start + 1、end := end - 1
- 文字列長が偶数で、かつ
temp1またはtemp2が空でない場合は、ans := ans + 1とします。 ansを返します。
Pythonでの実装例
以下のコードで実際の動作を確認できます。
class Solution(object):
def longestDecomposition(self, text):
start = 0
end = len(text) - 1
temp1 = ""
temp2 = ""
ans = 1 if len(text) & 1 else 0
while start < end:
temp1 += text[start]
temp2 = text[end] + temp2
if temp1 == temp2:
temp1 = temp2 = ""
ans += 2
start += 1
end -= 1
if len(text) % 2 == 0 and (temp1 or temp2):
ans += 1
return ans
ob = Solution()
print(ob.longestDecomposition("antaprezatepzapreanta"))
入力
"antaprezatepzapreanta"
出力
11
まとめ
このアルゴリズムは、左右から1文字ずつ付け足しながら一致を判定するシンプルな貪欲法です。一致した時点でできるだけ早く分割を確定させることで、最大のチャンク数を得られます。最悪計算量は O(n²) となりますが、実装が非常に分かりやすく、LeetCode の「Longest Chunked Palindrome Decomposition」のような文字列操作系の問題にもそのまま応用できる考え方です。
-
Pythonで文字列配列の最長共通プレフィックスを求める方法
配列に複数の文字列が格納されている場合、それらの文字列に共通する最長共通プレフィックス(Longest Common Prefix)を見つける必要があります。ここでは、すべての文字列が小文字であると仮定します。また、共通のプレフィックスが存在しない場合は空文字列 を返すものとします。 例えば、文字列の配列が [school, schedule, scotland] のような場合、すべての文字列に共通して含まれているのは sc であるため、最長共通プレフィックスは sc となります。 解決のアプローチ この問題を解くためには、以下の手順で処理を進めます。 最初の文字列を基準(current)
-
Pythonで整数が回文数(パリンドローム)かどうかを判定する方法
整数が与えられたとき、それが回文数(パリンドローム)であるかどうかを判定する方法を解説します。回文数とは、前から読んでも後ろから読んでも同じ並びになる数値のことです。例えば「454」は逆順にしても「454」となるため回文数です。一方、「-565」を逆順にすると「565-」となり、マイナス記号の位置が変わるため元の数と一致せず、回文数にはなりません。解法の考え方この問題は非常にシンプルに解けます。手順は以下の通りです。1. 数値をstr()で文字列に変換する2. Pythonのスライス記法[::-1]を使って文字列を反転させる3. 元の文字列と反転した文字列を比較し、一致すればTrue、一致しな