Как уже указывалось, эта проблема аналогична более известной проблеме расстояния редактирования (лежащей в основе расстояния Левенштейна ). Он также имеет общие черты, например, с расстоянием динамического коробления во времени (дублирование или «заикание» в вашем последнем требовании).
Шаги к динамическому программированию
x=x1…xny=y1…ymd(x,y)
min⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪d(x,y1…ym−1)+1d(x,y2…ym)+1d(x,y1…ym/2)+1d(x1…xn/2,y)+1d(x1…xn,y)+1d(x1…xn−1,y1…ym−1)if y=y1…ym/2y1…ym/2if x=x1…xn/2x1…xn/2if yn=ym▻ Add letter at end▻ Add letter at beginning▻ Doubling▻ Halving▻ Deletion▻ Ignoring last elt.
Здесь последний вариант в основном говорит, что преобразование FOOX в BARX эквивалентно преобразованию FOO в BAR. Это означает, что вы можете использовать опцию «добавить букву в конце», чтобы добиться эффекта заикания (дублирования) и удаления в точке. Проблема заключается в том, что она автоматически позволяет добавлять произвольный символ в середине строки , а , что - то вы , вероятно , не хотите. (Это «игнорирование идентичных последних элементов» является стандартным способом достижения удаления и заикания в произвольных позициях. Оно действительно запрещает произвольные вставки, хотя допускает добавления на любом конце, хотя и немного сложно, но…)
Я включил эту разбивку, даже если она не выполняет всю работу полностью, на случай, если кто-то другой может каким-то образом ее «спасти», и потому что я использую ее в своем эвристическом решении ниже.
(Конечно, если бы вы могли получить такую разбивку, которая фактически определяла ваше расстояние, вам нужно было бы только добавить памятку, и у вас было бы решение. Однако, поскольку вы работаете не только с префиксами, я не Не думаю, что вы могли бы использовать только индексы для своей заметки; вам, возможно, придется хранить фактические, измененные строки для каждого вызова, которые будут огромными, если ваши строки имеют значительный размер.)
Шаги к эвристическому решению
Другой подход, который может быть проще для понимания и который может занимать немного меньше места, - это поиск кратчайшего «пути редактирования» от вашей первой строки ко второй, используя алгоритм (в основном, лучше всего первая ветвь и связка). Пространство поиска будет определяться непосредственно вашими операциями редактирования. Теперь, для большой строки, вы быA∗получить большую окрестность, так как вы можете удалить любой символ (давая вам соседа для каждого потенциального удаления), или дублировать любой символ (опять же, давая вам линейное число соседей), а также добавить любой символ на любом конце, что будет дать вам количество соседей, равное удвоенному размеру алфавита. (Просто надеюсь, что вы не используете полный Unicode ;-) С таким большим разветвлением, вы можете достичь довольно существенного ускорения, используя двунаправленный или некоторый родственникA∗ .
Чтобы заставить работать, вам понадобится нижняя граница для оставшегося расстояния до вашей цели. Я не уверен, есть ли здесь очевидный выбор, но вы могли бы реализовать решение для динамического программирования, основанное на рекурсивной декомпозиции, которую я дал выше (опять же, с возможными проблемами с пространством, если ваши строки очень длинные). Несмотря на то , что разложение не точно вычислить дистанцию, то это гарантированно будет нижней границей (потому что это более снисходительными), что означает , что он будет работать как эвристика в . (Насколько это будет сложно, я не знаю, но это было бы правильно.) Конечно, памятка о вашей связанной функции может быть общей для всех вычислений границы во время вашегоA∗A∗A∗запустить. (Временной / пространственный компромисс там.)
Так…
Эффективность предложенного мной решения, похоже, сильно зависит от (1) длины ваших строк и (2) размера вашего алфавита. Если ни один не огромен, это могло бы работать. Это:
- Реализуйте нижнюю границу вашего расстояния, используя мою рекурсивную декомпозицию и динамическое программирование (например, используя запомненную рекурсивную функцию).
- Реализуйте (или двунаправленный ) с вашими операциями редактирования в виде «перемещений» в пространстве состояний и нижней границей на основе динамического программирования.A∗A∗
Я не могу дать никаких гарантий того, насколько эффективно это будет, но это должно быть правильно, и это, вероятно, будет намного лучше, чем решение методом перебора.
Если ничего другого, я надеюсь, что это даст вам некоторые идеи для дальнейших исследований.