У меня довольно сложная проблема поиска, которую мне удалось свести к следующему описанию. Я гуглил, но не смог найти алгоритм, который, кажется, полностью соответствует моей проблеме. В частности, необходимо пропустить произвольные целые числа. Может быть, кто-то здесь может указать мне на что-то?
Возьмем последовательность целых чисел A, например (1 2 3 4)
Возьмите различные последовательности целых чисел и проверьте, совпадает ли любая из них с A, что.
- A содержит все целые числа в проверенной последовательности
- Порядок целых чисел в тестируемой последовательности одинаков в A
- Нам нет дела до целых чисел в A, которых нет в тестовой последовательности
- Нам нужны все соответствующие тестовые последовательности, а не только первая.
Пример
A = (1 2 3 4)
B = (1 3)
C = (1 3 4)
D = (3 1)
E = (1 2 5)
B соответствует A
С соответствует А
D не соответствует A, так как порядок отличается
E не соответствует A, так как содержит целое число, не входящее в A
Я надеюсь, что это объяснение достаточно ясно. Лучшее, что мне удалось сделать, - это построить дерево тестовых последовательностей и выполнить итерации по A. Необходимость пропустить целые числа приводит к множеству неудачных путей поиска.
Благодарность
Читая некоторые предложения, я чувствую, что должен уточнить пару моментов, которые я оставил слишком расплывчатыми.
Допускаются повторные числа, на самом деле это очень важно, так как позволяет одной тестовой последовательности соответствовать A несколькими способами
A = (1234356), B = (236), совпадения могут быть либо -23 --- 6, либо -2--3-6.
Я ожидаю, что будет очень большое количество тестовых последовательностей, по крайней мере, тысяч, и последовательность A будет иметь максимальную длину, может быть, 20. Таким образом, простая попытка сопоставить каждую тестовую последовательность одну за другой путем итерации становится крайне неэффективной.
Извините, если это не было ясно.
источник
Ответы:
Хм, я могу вспомнить два возможных алгоритма: линейное сканирование последовательности A или построение словаря с постоянным поиском индексов.
Если вы тестируете много потенциальных подпоследовательностей B против одной большой последовательности A , я бы посоветовал вам использовать вариант со словарем.
Линейное сканирование
Описание
Мы поддерживаем курсор для последовательности A . Затем мы перебираем все элементы в подпоследовательности B . Для каждого элемента мы перемещаем курсор вперед по A, пока не найдем соответствующий элемент. Если соответствующий элемент не был найден, то B не является подпоследовательностью.
Это всегда работает в O (seq.size) .
ПСЕВДОКОД
Императивный стиль:
Функциональный стиль:
Пример реализации (Perl):
Поиск по словарю
Описание
Мы сопоставляем элементы последовательности A с их индексами. Затем мы ищем подходящие индексы для каждого элемента в B , пропускаем те индексы, которые являются маленькими, и выбираем наименьший возможный индекс в качестве нижнего предела. Если индексы не найдены, то B не является подпоследовательностью.
Работает в чем-то вроде O (subseq.size · k) , где k описывает, сколько в них повторяющихся чисел
seq
. Плюс O (seq.size) накладные расходыПреимущество этого решения заключается в том, что отрицательное решение может быть принято гораздо быстрее (вплоть до постоянного времени), как только вы заплатите за сборку справочной таблицы.
псевдокод:
Императивный стиль:
Функциональный стиль:
Пример реализации (Perl):
Вариант поиска по словарю: кодирование как конечный автомат
Описание
Мы можем еще больше уменьшить алгоритмическую сложность до O (subseq.size), если будем торговать большим объемом памяти. Вместо того, чтобы сопоставлять элементы с их индексами, мы создаем график, где каждый узел представляет элемент в своем индексе. Ребра показывают возможные переходы, например, последовательность
a, b, a
будет иметь ребраa@1 → b@2, a@1 → a@3, b@2 → a@3
. Этот граф эквивалентен конечному автомату.Во время поиска мы поддерживаем курсор, который изначально является первым узлом дерева. Затем мы ходить края для каждого элемента в Подсписок B . Если такого ребра не существует, то B не является подсписком. Если после всех элементов курсор содержит действительный узел, то B является подсписком.
ПСЕВДОКОД
Императивный стиль:
Функциональный стиль:
Пример реализации (Perl):
источник
study
работает и могут ли алгоритмы, которые он применяет, иметь здесь некоторое практическое применение?study
ранее построил таблицы поиска персонажа в позиции, мало чем отличаясь от моего второго решения.Вот практический подход, который избегает «тяжелой работы» по реализации собственного алгоритма, а также избегает «изобретать колесо»: использовать механизм регулярных выражений для решения проблемы.
Просто поместите все числа A в строку, а все числа B в строку, разделенные регулярным выражением
(.*)
. Добавьте^
символ в начале и$
в конце. Тогда пусть ваш любимый движок регулярных выражений ищет все совпадения. Например, когдаA = (1234356), B = (236)
создать reg exp для B как
^(.*)2(.*)3(.*)6(.*)$
. Теперь запустите глобальный поиск по регулярному выражению. Чтобы выяснить, в каких позициях в A соответствует ваша подпоследовательность, просто проверьте длину первых 3 подсовпадений.Если ваш диапазон целых чисел составляет от 0 до 9, вы можете сначала закодировать их по одной букве, чтобы сделать эту работу, или вам нужно адаптировать идею, используя символ разделения.
Конечно, скорость этого подхода будет во многом зависеть от скорости используемого вами механизма reg exp, но есть высоко оптимизированные доступные движки, и я думаю, что будет сложно реализовать более быстрый алгоритм «из коробки» ,
источник
Этот алгоритм должен быть достаточно эффективным, если эффективны получение длины и повторение последовательности.
sequence
и корочеsubsequence
sequence
.sequence
равно числу в текущей позицииsubsequence
sequence
одинsubsequence
в концеsequence
источник