Вот проблема, которая беспокоила меня некоторое время. Допустим, строка представляет собой последовательность из 1 и 0, а строка с подстановочными символами - это последовательность из 1, 0 и? S. Все строки и строки шаблона имеют одинаковую длину. Это стандартные подстановочные знаки UNIX; 10 ?? 1 соответствует 10011, 10111 и т. Д. - а? соответствует 1 или 0 в этой позиции. Если а также являются шаблонными строками, тогда мы пишем если каждая строка соответствует также соответствует ,
Проблемы : дан набор подстановочных строк и запрос (также подстановочная строка), существует ли такой, что ? А если нет, можем ли мы добавить в эффективно?
Вот очевидное решение (где это размер строк, это размер слова ОЗУ (обычно 32 или 64)): просмотрите каждый элемент списка и проверьте условие (которое может быть выполнено в 2 или 3 операциях с использованием бит-тиддлинга). Также проверьте, если вмещает любой предмет пока мы сканируем Если не проходит наш тест, затем добавьте к набору, и удалите Мы отметили.
Но это не достаточно быстро. Было бы здорово, если бы решение или, в идеальном мире, сложность, подобная основному дереву (). Также нормально, чтобы запросы были примерно правильными : еслизатем верните да или нет; но если условие не выполняется, обязательно верните no.
Хотя это не помогает в худшем случае, вы можете предположить, что все элементы в ограничены подстановочной строкой; то есть существует такой, что для всех , ,
Идеи, которые я пробовал
- Строка подстановочных знаков образует полурешетку соединения. У нас может быть n-арное дерево, содержащее подстановочные строки; листья были бы подстановочными символами, а ветви - объединением всех детей. Если запрос и объединение несопоставимы, нам не нужно тратить время на сравнение со всеми дочерними элементами этой ветви. Кроме того, если мы производим обновление, а обновление оказывается больше, чем объединение, мы можем просто удалить всю ветку. К сожалению, это все еще в худшем случае, и мы не всегда находим «лучшие» объединения для сканирования при добавлении элементов в дерево.
- Можно сформировать корень из , Мы знаем этоограничен некоторой подстановочной строкой; Предположим, что это? 0? 0. Тогда все ветви дерева должны быть только на 1-м и 3-м битах строк. Если текущий бит, на который мы выполняем ответвление, равен 1, мы должны проверить? и 1 филиал; если это 0, мы проверяем? и 0 веток; если это так, мы только проверяем? филиал. Поскольку нам потенциально приходится брать несколько веток, это не очень хорошо (сложно обновить дерево по той же причине). Поскольку сопоставление является очень очень быстрой операцией, по сравнению с наивной стратегией больно выполнять много обходов в дереве (следование куче указателей намного дороже, чем выполнение некоторых OR и AND).
Связанных с работой
В сетевом сообществе эта проблема проявляется как «классификация пакетов», здесь представлен хороший обзор известных алгоритмов и структур данных . К сожалению, почти всегда делается предположение, что подстановочные строки соответствуют только префиксам, и запрос является кортежем таких строк. Конечно, мы всегда можем преобразовать общую подстановочную строку для соответствия этим критериям: 1? 00? 1 ?? есть (1,?, 0, 0,?, 1,?,?). Это не будет эффективным, хотя. Другое предположение состоит в том, что эти кортежи связаны с «цветом», и запрос должен возвращать цвет (а не только то, что он соответствует). Это делает проблему намного сложнее, потому что мы должны упорядочить кортежи (или это неоднозначно, какой из (0,?) И (?, 1) соответствует (0, 1)).
В сообществе алгоритмов я нашел много результатов, связанных с поиском подстрок, которые соответствуют "пофиг". Это значительно более сложная проблема, и я не могу использовать ни одну из техник.
В заключении
Спасибо за любую помощь!
источник
Ответы:
Как насчет использования конечного автомата? ЯзыкS конечно и, следовательно, регулярно. Даже после приведенных ниже преобразований все равно будет регулярно. Поэтому после обычных шагов по преобразованию регулярного выражения в детерминированный конечный автомат у вас будет распознаватель того, что вы хотите, который работает вO ( k ) время. Надеюсь, что эта идея все еще будет работать, если есть ошибки в том, что предлагается ниже.
Проблема в том, как бороться с подстановочным оператором: Подстановочный знак в подстановочной строке соответствует 0 или 1 в тестовой строке. Но поскольку мы пытаемся распознать подстановочные знаки, подстановочный знак в подстановочной строке соответствует 0, 1 или? в другой строке шаблона. Этот набор все еще регулярен, поэтому мы преобразовываем каждое вхождение? к регулярному выражению (0 | 1 |?), где вертикальная черта - обычный оператор чередования. Так что если весь ваш наборS равен {10 ?? 1, 0? 1? 0}, результирующее регулярное выражение будет (10 (0 | 1 |?) (0 | 1 |?) 1 | 0 (0 | 1 |?) 1 (0 | 1 |?) 0)
Что касается добавления строк в машину, недавно была проведена работа по постепенному изменению конечного автомата. См. Эту статью Daciuk et al. «Инкрементальное построение минимальных ациклических конечных автоматов».
Это помогает?
источник