文字列(英語の文字のみを想定)S
の長さn
を指定すると、次のアルゴリズムで回文部分文字列の数をカウントできます。
_for i = 0 to |S| do
p1 = number of palindromes centered in i (odd length)
p2 = number of palindromes centered in i and i+1 (even length)
add p1 + p2 to total number of palindromic substrings of S
_
上記のコードはO(n^2)
です。
この問題をO(n)
で解決するアルゴリズムに興味があります。複数の人がそうだと言っているのを聞いたので、確かに存在します。問題は、n
の上限が_1 000 000
_であるローカルのオンライン裁判官サイトにありますが、私はアルゴリズムを見たことがなく、アルゴリズムを思い付くことができないようです。
更新:
私が持っている一般的な考え方は、_len[i] = length of the longest palindrome centered at the character 2i + 1
_と同様の長さの偶数長の回文の配列を計算することです。優れた簿記があれば、これを各文字のO(1)
で計算できるはずです。これにより、多くの回文を一度に数えることができます。しかし、これを正確に計算する方法にこだわっています。
O(n)
とO(n log n)
の追加メモリを使用するソリューションを受け入れます。これなしではこれは不可能だと思います。
良いアイデアや参考文献はありがたいです。
次のサイトは、O(n)時間で最長の回文部分文字列を計算するためのアルゴリズムを示しています。可能な限りすべての中心で最長の回文部分文字列を計算し、最大値をとることによって計算します。目的に合わせて簡単に変更できるはずです。
http://www.akalin.cx/2007/11/28/finding-the-longest-palindromic-substring-in-linear-time/
編集:最初のリンクはよく見ると少し不安定に見えるので、別のリンクを次に示します。
http://zhuhcheng.spaces.live.com/Blog/cns!DE38E96268C49F28!311.entry?wa=wsignin1.0&sa=707413829
「通常の」文字列の場合は、各文字を回文の潜在的な「中心」と見なして、周囲の文字が実際に1つを構築しているかどうかを確認する方が効率的です。
# check odd palindromes
for center in range(len(ls)):
# check how many characters to the left and right of |center|
# build a palindrome
maxoffs = min(center, len(ls)-center-1)
offs = 0
while offs <= maxoffs and ls[center-offs] == ls[center+offs]:
offs += 1
offs -= 1
print ls[center-offs : center+offs+1]
# check for even palindromes
for center in range(len(ls)-1):
maxoffs = min(center, len(ls)-center-2)
offs = 0
while offs <= maxoffs and ls[center-offs] == ls[center+offs+1]:
offs += 1
offs -= 1
if offs >= 0:
print ls[center-offs : center+offs+2]
通常の文字列の場合、これは約O(n)になりますが、最悪の場合、たとえば、文字列が1文字だけで何度も繰り返されている場合でも、O(n)がかかります2)時間。
文字列S="aaabb"
を考えます。
文字列の両端と2つの連続する文字の間に文字'$'
を追加して、文字列をS="$a$a$a$b$b$"
に変更し、この文字列に Manacher's algorithm を適用しますS
。
新しい文字列S
の長さは2n + 1で、O(n)と同じO(2n + 1)のランタイムを提供します。
index : 1 2 3 4 5 6 7 8 9 10 11
A : 1 3 5 7 5 3 1 3 5 3 1
S : $ a $ a $ a $ b $ b $
配列A
はManacherのアルゴリズムの結果です。
ここで、インデックスのA[i]/4
の合計、ここで'$'
、それ以外の場合は1 <= i <= nの他のすべての文字の(A[i]+1)/4
が答えです。
ここで、$
は、偶数長のパリドロームのサブストリングの中心として機能し、奇数長は通常どおり計算できます。この場合の答えは次のとおりです。
0 + 1 + 1 + 2 + 1 + 1 + 0 + 1 + 1 + 1 + 0 = 9(a、a、aaa、a、b、b、aa、aa、bb)。