圧縮されたドキュメントの長さを N とします。
b(n) をブール値とします。ドキュメント内の位置 n から始まる単語にドキュメントを分割できる場合は true です。
b(N) は true です (空の文字列は 0 語に分割できるため)。b(N)、b(N - 1)、... b(N - k) が与えられた場合、文字 N - k - 1 で始まるすべての単語を考慮して、b(N - k - 1) を作成できます。 b(N - k - 1 + len(w)) が設定されたそのような単語 w の場合は、b(N - k - 1) を true に設定します。そのような単語がない場合は、b(N - k - 1) を false に設定します。
最終的に、ドキュメント全体を単語に分割できるかどうかを示す b(0) を計算します。
擬似コード:
def try_to_split(doc):
N = len(doc)
b = [False] * (N + 1)
b[N] = True
for i in range(N - 1, -1, -1):
for word starting at position i:
if b[i + len(word)]:
b[i] = True
break
return b
「位置 i から始まる単語」を効率的にするためにできるトリックがいくつかありますが、O(N^2) アルゴリズムを求められるので、辞書で i から始まるすべての文字列を調べるだけで済みます。
単語を生成するには、上記のアルゴリズムを変更して適切な単語を保存するか、次のように生成します。
def generate_words(doc, b, idx=0):
length = 1
while true:
assert b(idx)
if idx == len(doc): return
word = doc[idx: idx + length]
if word in dictionary and b(idx + length):
output(word)
idx += length
length = 1
ここで、b はアルゴリズムの最初の部分から生成されたブール配列です。