pkpnd ответ по правильному пути. Но словари имеют тенденцию быть довольно большими наборами, и итерации по всему словарю для каждого символа строки будут неэффективными. (Кроме того, сохранение всей последовательности для каждой ячейки dp может занять много места.) Скорее, мы можем сформулировать вопрос, перебирая строку, следующим образом: учитывая все предыдущие индексы строки, для которых словарь соответствует расширению назад (либо к началу, либо к другому совпадению), которое является словарным совпадением, когда мы включаем текущий символ, и имеет в целом меньшую длину. В целом:
f(i) = min(
f(j) + length(i - j) + (1 if j is after the start of the string)
)
for all j < i, where string[j] ended a dictionary match
and string[j+1..i] is in the dictionary
Поскольку мы добавляем еще один j
только при наличии совпадения, а новое совпадение может распространяться только на предыдущее совпадение или на начало строки, наша структура данных может быть массивом кортежей, (best index this match extends back to, total length up to here)
. Мы добавляем еще один кортеж, если текущий символ может расширить словарное совпадение до другой записи, которая у нас уже есть. Мы также можем оптимизировать, выйдя рано из поиска в обратном направлении, когда соответствующая подстрока станет больше, чем самое длинное слово в словаре, и создав подстроку для сравнения со словарем, когда мы выполняем итерацию в обратном направлении.
Код JavaScript:
function f(str, dict){
let m = [[-1, -1, -1]];
for (let i=0; i<str.length; i++){
let best = [null, null, Infinity];
let substr = '';
let _i = i;
for (let j=m.length-1; j>=0; j--){
let [idx, _j, _total] = m[j];
substr = str.substr(idx + 1, _i - idx) + substr;
_i = idx;
if (dict.has(substr)){
let total = _total + 1 + i - idx;
if (total < best[2])
best = [i, j, total];
}
}
if (best[0] !== null)
m.push(best);
}
return m;
}
var s = "ilikealibaba";
var d = new Set(["i", "like", "ali", "liba", "baba", "alibaba"]);
console.log(JSON.stringify(f(s,d)));
Мы можем отследить наш результат:
[[-1,-1,-1],[0,0,1],[4,1,6],[7,2,10],[11,2,14]]
[11, 2, 14] means a total length of 14,
where the previous index in m is 2 and the right index
of the substr is 11
=> follow it back to m[2] = [4, 1, 6]
this substr ended at index 4 (which means the
first was "alibaba"), and followed m[1]
=> [0, 0, 1], means this substr ended at index 1
so the previous one was "like"
И вот оно: «Мне нравится алибаба»