問題にチャレンジして、ユーザー同士で解答を教え合ったり、コードを公開してみよう!
前回までで、最長共通接頭辞の性質を利用した効率的な Z 配列の計算方法について学びました。あとは、各左端に対して、Z 配列の値を求める際に、最長共通接頭辞の性質を利用して Z 配列を効率的に更新していけば、Z 配列を非常に効率的に求めることができます。このように、最長共通接頭辞の性質を利用して時間計算量 O(|s|) で計算するアルゴリズムを Z-Algorithm といいます。
では、実際に Z-Algorithm を実装してみましょう。
Z 配列を求める単純なアルゴリズムは以下のようなものでした。
for i = 0 から |s| - 1 まで:
while i + z[i] < |s| かつ s[z[i]] == s[i + z[i]]:
z[i]++;
j = 0
for i = 0 から |s| - 1 まで:
if j != 0 かつ i < j + z[j]:
z[i] = min(z[i - j], j + z[j] - i)
if j == 0 または j + z[j] <= i + z[i]:
while i + z[i] < |s| かつ s[z[i]] == s[i + z[i]]:
z[i]++;
j = i
s
s の Z 配列 z_1, z_2, ..., z_|s| を改行区切りで出力してください。
また、末尾に改行を入れ、余計な文字を含んではいけません。
すべてのテストケースにおいて、以下の条件をみたします。
・ 1 ≦ |s| ≦ 100000 = 10^5
・ s は英小文字のみからなる文字列
abcabcabcabc
12
0
0
9
0
0
6
0
0
3
0
0