Рассмотрим сначала простейший случай K = 1. Как проверить, мог ли Вася, сказав слово T, иметь в виду P? Для этого будем просто бежать по T одним циклом, также используя счетчик j, равный сначала 1. Как только текущий символ T совпадает с P[j], надо увеличить j на единицу. Если J так и не превысил m, то не найдется последовательности, удовлетворяющей определению (иначе алгоритм бы ее нашел), и Вася не мог иметь P в виду. В противном случае --- последовательность существует и ответ положительный. Такой алгоритм работает за O(n), где n --- длина T.
Если применять этот способ для каждого словарного слова, может получиться так, что по T вы пробежимся K раз --- а это слишком долго.
Для решения данной задачи используется идея, позволяющая проверять слово P длины m за m действий (конечно, с некоторой предподготовкой для T).
Пусть next[i][x] --- минимальная (самая правая позиция) вхождения символа x в T, начиная с i + 1 (здесь 0 < i < n + 1). Другими словами,
next[i][x] = min{ j: j > i и T[j] = x }.
Если такого символа нет правее позиции i, то будем считать next[i][x] = -1.
Чтобы вычислить next, будем бежать c конца T, поддерживая в массиве last[‘a’..‘z’] искомые ближайшие позиции для каждого символа:
for c := ‘a’ to ‘z’ do last[c] := -1;
for i := n downto 0 do begin
for c := ‘a’ to ‘z’ do next[i][c] := last[c];
if (i > 0) then last[T[i]] := i;
end;
С помощью next легко модифицировать старый алгоритм, чтобы он уже работал за O(m):
j := 1;
I := 0;
While (j <= m) do begin
I := next[i][P[j]];
If (I = -1) then break;
J := j + 1;
End;
Аналогично, если j получилось больше m, то найдется последовательность, удовлетворяющая определению, то есть Вася мог иметь в виду P. В противном случае (j <= m) такой последовательности нет.
Чтобы проверить все K словарных слов, потребуется S (суммарная длина всех слов) + T*26 (расходы по вычислению next), получаем 3.6*10^6 в худшем случае. Как известно, такая оценка для алгоритма приемлема.